RDS
caution
This is the SST v1.x Constructs doc. SST v2 is now released. If you are using v2, see the v2 Constructs doc. If you are looking to upgrade to v2, check out the upgrade steps.
The RDS
construct is a higher level CDK construct that makes it easy to create an RDS Serverless Cluster. It uses the following defaults:
- Defaults to using the Serverless v1 On-Demand autoscaling configuration to make it serverless.
- Provides a built-in interface for running schema migrations using Kysely.
- Enables Data API to allow your Lambda functions to access the database cluster without needing to deploy the functions in a VPC (virtual private cloud).
- Enables Backup Snapshot to make sure that you don't lose your data.
Migrations
The RDS
construct uses Kysely to run and manage schema migrations. The migrations
prop should point to the folder where your migration files are.
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "acme",
migrations: "path/to/migration/scripts",
});
On sst deploy
, all migrations that have not yet been run will be run as a part of the deploy process. The migrations are executed in alphabetical order by their name.
On sst start
, migrations are not automatically run. You can manually run them via the SST Console.
note
New migrations must always have a name that comes alphabetically after the last executed migration.
Migration files should have the following format.
async function up(db) {
// Migration code
}
async function down(db) {
// Migration code
}
module.exports = { up, down };
Read more about writing migrations over on the Kysely docs.
Migrations with PostgreSQL
async function up(db) {
await db.schema
.createTable("person")
.addColumn("id", "serial", (col) => col.primaryKey())
.addColumn("first_name", "varchar", (col) => col.notNull())
.addColumn("last_name", "varchar")
.addColumn("gender", "varchar(50)", (col) => col.notNull())
.execute()
}
async function down(db) {
await db.schema.dropTable("person").execute()
}
module.exports = { up, down };
Migrations with MySQL
async function up(db) {
await db.schema
.createTable("person")
.addColumn("id", "integer", (col) => col.autoIncrement().primaryKey())
.addColumn("first_name", "varchar(255)", (col) => col.notNull())
.addColumn("last_name", "varchar(255)")
.addColumn("gender", "varchar(50)", (col) => col.notNull())
.execute()
}
async function down(db) {
await db.schema.dropTable("person").execute()
}
module.exports = { up, down };
Auto-scaling
RDS automatically scales the cluster size based on CPU utilization, connections, and available memory. An RDS with the MySQL engine can scale from 1 to 256 ACU (Aurora capacity unit). And an RDS with the PostgreSQL engine can scale from 2 to 384 ACU. You can specify the minimum and maximum range for the cluster. The default minimum and maximum capacity are 2 and 16 ACU.
You can also choose to pause your RDS cluster after a given amount of time with no activity. When the cluster is paused, you are charged only for the storage. If database connections are requested when a cluster is paused, the cluster automatically resumes. By default, the cluster auto-pauses after 5 minutes of inactivity.
For dev stages, it makes sense to pick a low capacity and auto-pause time. And disable it for production stages.
const prodConfig = {
autoPause: false,
minCapacity: "ACU_8",
maxCapacity: "ACU_64",
};
const devConfig = {
autoPause: true,
minCapacity: "ACU_2",
maxCapacity: "ACU_2",
};
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "acme",
scaling: app.stage === "prod" ? prodConfig : devConfig,
});
Read more over on the RDS docs.
Examples
Using the minimal config
import { RDS } from "@serverless-stack/resources";
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "my_database",
});
Configuring the RDS cluster
You can configure the internally created CDK ServerlessCluster
instance.
import * as cdk from "aws-cdk-lib";
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "acme",
cdk: {
cluster: {
backupRetention: cdk.Duration.days(7),
},
},
});
Advanced examples
Import existing RDS Serverless v1 cluster
import * as rds from "aws-cdk-lib/aws-rds";
import * as secretsManager from "aws-cdk-lib/aws-secretsmanager";
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "acme",
cdk: {
cluster: rds.ServerlessCluster.fromServerlessClusterAttributes(stack, "ICluster", {
clusterIdentifier: "my-existing-cluster",
}),
secret: secretsManager.Secret.fromSecretAttributes(stack, "ISecret", {
secretPartialArn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret",
}),
},
});
Note that migrations are support for imported cluster. In order for migrations to work, make sure engine
and defaultDatabaseName
match the configuration of the imported cluster. You also need to import the secret credentials used by the cluster from the Secrets Manager.
Using existing VPC
The RDS
construct automatically creates a VPC to deploy the cluster. This VPC contains only PRIVATE and ISOLATED subnets, without NAT Gateways.
note
Since we are using the Data API, you don't need to deploy your Lambda functions into the RDS's VPC.
Yo can override the internally created VPC
instance.
import * as ec2 from "aws-cdk-lib/aws-ec2";
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "acme",
cdk: {
cluster: {
vpc: ec2.Vpc.fromLookup(this, "VPC", {
vpcId: "vpc-xxxxxxxxxx",
}),
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE,
},
},
},
});
Constructor
new RDS(scope, id, props)
Parameters
RDSProps
defaultDatabaseName
Type : string
Name of a database which is automatically created inside the cluster.
engine
Type : "mysql5.6" | "mysql5.7" | "postgresql11.13" | "postgresql11.16" | "postgresql13.19"
Database engine of the cluster. Cannot be changed once set.
migrations?
Type : string
Path to the directory that contains the migration scripts. The RDS
construct uses Kysely to run and manage schema migrations. The migrations
prop should point to the folder where your migration files are.
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "acme",
migrations: "path/to/migration/scripts",
});
scaling.autoPause?
Type : number | boolean
Default : true
The time before the cluster is paused. Pass in true to pause after 5 minutes of inactive. And pass in false to disable pausing.
Or pass in the number of minutes to wait before the cluster is paused.
new RDS(stack, "Database", {
scaling: {
autoPause: props.app.stage !== "prod"
}
})
scaling.maxCapacity?
Type : "ACU_1" | "ACU_2" | "ACU_4" | "ACU_8" | "ACU_16" | "ACU_32" | "ACU_64" | "ACU_128" | "ACU_192" | "ACU_256" | "ACU_384"
Default : "ACU_16"
The maximum capacity for the cluster.
scaling.minCapacity?
Type : "ACU_1" | "ACU_2" | "ACU_4" | "ACU_8" | "ACU_16" | "ACU_32" | "ACU_64" | "ACU_128" | "ACU_192" | "ACU_256" | "ACU_384"
Default : "ACU_2"
The minimum capacity for the cluster.
types?
Type : string | RDSTypes
Path to place generated typescript types after running migrations
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "acme",
migrations: "path/to/migration/scripts",
types: "backend/core/sql/types.ts",
});
new RDS(stack, "Database", {
engine: "postgresql11.13",
defaultDatabaseName: "acme",
migrations: "path/to/migration/scripts",
types: {
path: "backend/core/sql/types.ts",
camelCase: true
}
});
cdk.cluster?
Type : IServerlessCluster | RDSCdkServerlessClusterProps
Configure the internallly created RDS cluster.
new RDS(stack, "Database", {
cdk: {
cluster: {
clusterIdentifier: "my-cluster",
}
},
});
Alternatively, you can import an existing RDS Serverless v1 Cluster in your AWS account.
new RDS(stack, "Database", {
cdk: {
cluster: rds.ServerlessCluster.fromServerlessClusterAttributes(stack, "ICluster", {
clusterIdentifier: "my-cluster",
}),
secret: secretsManager.Secret.fromSecretAttributes(stack, "ISecret", {
secretPartialArn: "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret",
}),
},
});
cdk.id?
Type : string
Allows you to override default id for this construct.
cdk.secret?
Type : ISecret
Required when importing existing RDS Serverless v1 Cluster.
Properties
An instance of RDS
has the following properties.
clusterArn
Type : string
The ARN of the internally created RDS Serverless Cluster.
clusterEndpoint
Type : Endpoint
The ARN of the internally created RDS Serverless Cluster.
clusterIdentifier
Type : string
The ARN of the internally created RDS Serverless Cluster.
defaultDatabaseName
Type : string
The default database name of the RDS Serverless Cluster.
id
Type : string
migratorFunction?
Type : Function
The ARN of the internally created CDK ServerlessCluster instance.
secretArn
Type : string
The ARN of the internally created Secrets Manager Secret.
cdk.cluster
Type : ServerlessCluster
The ARN of the internally created CDK ServerlessCluster instance.
RDSTypes
camelCase?
Type : boolean
path
Type : string
RDSCdkServerlessClusterProps
vpc?
Type : IVpc