Table
The Table
construct is a higher level CDK construct that makes it easy to create a DynamoDB table. It uses the following defaults:
- Defaults to using the On-Demand capacity to make it perfectly serverless.
- Enables Point-in-Time Recovery to make sure that you don't lose your data.
- Provides a nicer interface for defining indexes.
Examples
Primary index
import { Table } from "sst/constructs";
new Table(stack, "Notes", {
fields: {
userId: "string",
noteId: "string",
},
primaryIndex: { partitionKey: "noteId", sortKey: "userId" },
});
Global indexes
new Table(stack, "Notes", {
fields: {
userId: "string",
noteId: "string",
time: "number",
},
primaryIndex: { partitionKey: "noteId", sortKey: "userId" },
globalIndexes: {
userTimeIndex: { partitionKey: "userId", sortKey: "time" },
},
});
Configuring index projection
new Table(stack, "Table", {
fields: {
userId: "string",
noteId: "string",
time: "number",
},
primaryIndex: { partitionKey: "noteId", sortKey: "userId" },
globalIndexes: {
userTimeIndex: {
partitionKey: "userId",
sortKey: "time",
projection: "keys_only",
},
},
});
Local indexes
new Table(stack, "Notes", {
fields: {
userId: "string",
noteId: "string",
time: "number",
},
primaryIndex: { partitionKey: "noteId", sortKey: "userId" },
localIndexes: {
userTimeIndex: { sortKey: "time" },
},
});
DynamoDB Streams
Using the minimal config
Enable DynamoDB Streams and add consumers.
new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
stream: true,
consumers: {
consumer1: "src/consumer1.main",
consumer2: "src/consumer2.main",
},
});
Lazily adding consumers
Lazily add the consumers after the table has been defined.
const table = new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
stream: true,
});
table.addConsumers(stack, {
consumer1: "src/consumer1.main",
consumer2: "src/consumer2.main",
});
Specifying function props for all the consumers
You can extend the minimal config, to set some function props and have them apply to all the consumers.
new Table(stack, "Notes", {
defaults: {
function: {
timeout: 20,
environment: { topicName: topic.topicName },
permissions: [topic],
},
},
stream: true,
consumers: {
consumer1: "src/consumer1.main",
consumer2: "src/consumer2.main",
},
});
Using the full config
Configure each Lambda function separately.
new Table(stack, "Notes", {
stream: true,
consumers: {
consumer1: {
function: {
handler: "src/consumer1.main",
timeout: 10,
environment: { topicName: topic.topicName },
permissions: [topic],
},
},
},
});
Note that, you can set the defaults.function
while using the function
per consumer. The function
will just override the defaults.function
. Except for the environment
, the layers
, and the permissions
properties, that will be merged.
new Table(stack, "Notes", {
defaults: {
function: {
timeout: 20,
environment: { topicName: topic.topicName },
permissions: [topic],
},
},
stream: true,
consumers: {
consumer1: {
function: {
handler: "src/consumer1.main",
timeout: 10,
environment: { bucketName: bucket.bucketName },
permissions: [bucket],
},
},
consumer2: "src/consumer2.main",
},
});
So in the above example, the consumer1
function doesn't use the timeout
that is set in the defaults.function
. It'll instead use the one that is defined in the function definition (10 seconds
). And the function will have both the topicName
and the bucketName
environment variables set; as well as permissions to both the topic
and the bucket
.
Giving the consumers permissions
Allow the consumer functions to access S3.
const table = new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
stream: true,
consumers: {
consumer1: "src/consumer1.main",
consumer2: "src/consumer2.main",
},
});
table.attachPermissions(["s3"]);
Giving a specific consumer permissions
Allow the first consumer function to access S3.
const table = new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
stream: true,
consumers: {
consumer1: "src/consumer1.main",
consumer2: "src/consumer2.main",
},
});
table.attachPermissionsToConsumer("consumer1", ["s3"]);
Configuring the Stream content
Configure the information that will be written to the Stream.
new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
stream: "new_image",
consumers: {
consumer1: "src/consumer1.main",
consumer2: "src/consumer2.main",
},
});
Filtering events
new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
stream: true,
consumers: {
myConsumer: {
function: "src/consumer1.main",
filters: [
{
dynamodb: {
Keys: {
Id: {
N: ["101"],
},
},
},
},
],
},
},
});
Configuring a consumer
Configure the internally created CDK Event Source.
import { StartingPosition } from "aws-cdk-lib/aws-lambda";
new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
stream: true,
consumers: {
consumer1: {
function: "src/consumer1.main",
cdk: {
eventSource: {
startingPosition: StartingPosition.TRIM_HORIZON,
},
},
},
},
});
Kinesis Streams
import { KinesisStream } from "sst/constructs";
const stream = new KinesisStream(stack, "Stream");
new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
kinesisStream: stream,
});
Note, you do not need to configure the stream
and consumers
fields when enabling the Kinesis Streams. The stream
field is used to configure DynamoDB Streams, and the consumers
are only triggered by DynamoDB Streams.
You can read more about configuring consumers
for the Kinesis Stream in the KinesisStream
doc.
Advanced examples
Configuring the DynamoDB table
Configure the internally created CDK Table
instance.
import { RemovalPolicy } from "aws-cdk-lib";
new Table(stack, "Table", {
fields: {
userId: "string",
noteId: "string",
},
primaryIndex: { partitionKey: "noteId", sortKey: "userId" },
cdk: {
table: {
removalPolicy: RemovalPolicy.DESTROY,
},
},
});
Importing an existing table
Override the internally created CDK Table
instance.
import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
new Table(stack, "Table", {
cdk: {
table: dynamodb.Table.fromTableArn(stack, "ImportedTable", tableArn),
},
});
Enabling Global Tables
import { Duration } from "aws-cdk-lib";
const table = new Table(stack, "Notes", {
fields: {
noteId: "string",
},
primaryIndex: { partitionKey: "noteId" },
cdk: {
table: {
replicationRegions: ["us-east-1", "us-east-2", "us-west-2"],
replicationTimeout: Duration.hours(2),
},
},
});
Constructor
new Table(scope, id, props)
Parameters
- scope Construct
- id string
- props TableProps
TableProps
consumers?
Type : Record<string, string | Function | TableConsumerProps>
Configure DynamoDB streams and consumers
const table = new Table(stack, "Table", {
consumers: {
consumer1: "src/consumer1.main",
consumer2: "src/consumer2.main",
},
});
defaults?
Type :
defaults.function?
Type : FunctionProps
The default function props to be applied to all the consumers in the Table. The
environment
,
permissions
and
layers
properties will be merged with per route definitions if they are defined.
new Table(stack, "Table", {
defaults: {
function: {
timeout: 20,
environment: { topicName: topic.topicName },
permissions: [topic],
}
},
});
fields?
Type : Record<string, "string" | "number" | "binary">
An object defining the fields of the table. Key is the name of the field and the value is the type.
new Table(stack, "Table", {
fields: {
pk: "string",
sk: "string",
}
})
globalIndexes?
Type : Record<string, TableGlobalIndexProps>
Configure the table's global secondary indexes
new Table(stack, "Table", {
fields: {
pk: "string",
sk: "string",
gsi1pk: "string",
gsi1sk: "string",
},
globalIndexes: {
"GSI1": { partitionKey: "gsi1pk", sortKey: "gsi1sk" },
},
});
kinesisStream?
Type : KinesisStream
Configure the KinesisStream to capture item-level changes for the table.
const stream = new KinesisStream(stack, "Stream");
new Table(stack, "Table", {
kinesisStream: stream,
});
localIndexes?
Type : Record<string, TableLocalIndexProps>
Configure the table's local secondary indexes
new Table(stack, "Table", {
fields: {
pk: "string",
sk: "string",
lsi1sk: "string",
},
localIndexes: {
"lsi1": { sortKey: "lsi1sk" },
},
});
primaryIndex?
Type :
primaryIndex.partitionKey
Type : string
Define the Partition Key for the table's primary index
new Table(stack, "Table", {
fields: {
pk: "string",
},
primaryIndex: { partitionKey: "pk" },
});
primaryIndex.sortKey?
Type : string
Define the Sort Key for the table's primary index
new Table(stack, "Table", {
fields: {
pk: "string",
sk: "string",
},
primaryIndex: { partitionKey: "pk", sortKey: "sk" },
});
stream?
Type : boolean | "keys_only" | "new_image" | "old_image" | "new_and_old_images"
Configure the information that will be written to the Stream.
new Table(stack, "Table", {
stream: "new_image",
});
timeToLiveAttribute?
Type : string
The field that's used to store the expiration time for items in the table.
new Table(stack, "Table", {
timeToLiveAttribute: "expireAt",
});
cdk?
Type :
cdk.id?
Type : string
Allows you to override default id for this construct.
cdk.table?
Type : ITable | Omit<TableProps, "sortKey" | "partitionKey">
Override the settings of the internally created cdk table
Properties
An instance of Table
has the following properties.
id
Type : string
tableArn
Type : string
The ARN of the internally created DynamoDB Table.
tableName
Type : string
The name of the internally created DynamoDB Table.
cdk
Type :
cdk.table
Type : ITable
The internally created CDK
Table
instance.
Methods
An instance of Table
has the following methods.
addConsumers
addConsumers(scope, consumers)
Parameters
- scope Construct
- consumers
Define additional consumers for table events
table.addConsumers(stack, {
consumer1: "src/consumer1.main",
consumer2: "src/consumer2.main",
});
addGlobalIndexes
addGlobalIndexes(secondaryIndexes)
Parameters
- secondaryIndexes Record<string, TableGlobalIndexProps>
Add additional global secondary indexes where the
key
is the name of the global secondary index
table.addGlobalIndexes({
gsi1: {
partitionKey: "pk",
sortKey: "sk",
}
})
addLocalIndexes
addLocalIndexes(secondaryIndexes)
Parameters
- secondaryIndexes Record<string, TableLocalIndexProps>
Add additional local secondary indexes where the
key
is the name of the local secondary index
table.addLocalIndexes({
lsi1: {
sortKey: "sk",
}
})
attachPermissions
attachPermissions(permissions)
Parameters
- permissions Permissions
Grant permissions to all consumers of this table.
table.attachPermissions(["s3"]);
attachPermissionsToConsumer
attachPermissionsToConsumer(consumerName, permissions)
Parameters
- consumerName string
- permissions Permissions
Grant permissions to a specific consumer of this table.
table.attachPermissionsToConsumer("consumer1", ["s3"]);
bind
bind(constructs)
Parameters
- constructs Array<BindingResource>
Binds the given list of resources to all consumers of this table.
table.bind([STRIPE_KEY, bucket]);
bindToConsumer
bindToConsumer(consumerName, constructs)
Parameters
- consumerName string
- constructs Array<BindingResource>
Binds the given list of resources to a specific consumer of this table.
table.bindToConsumer("consumer1", [STRIPE_KEY, bucket]);
getFunction
getFunction(consumerName)
Parameters
- consumerName string
Get the instance of the internally created Function, for a given consumer.
const table = new Table(stack, "Table", {
consumers: {
consumer1: "./src/function.handler",
}
})
table.getFunction("consumer1");
TableConsumerProps
filters?
Type : Array<any>
Used to filter the records that are passed to the consumer function.
const table = new Table(stack, "Table", {
consumers: {
myConsumer: {
function: "src/consumer1.main",
filters: [
{
dynamodb: {
Keys: {
Id: {
N: ["101"]
}
}
}
}
]
}
},
});
function
Type : string | Function | FunctionProps
Used to create the consumer function for the table.
cdk?
Type :
cdk.eventSource?
Type : DynamoEventSourceProps
Override the settings of the internally created event source
TableLocalIndexProps
projection?
Type : Array<string> | "all" | "keys_only"
Default : "all"
The set of attributes that are projected into the secondary index.
sortKey
Type : string
The field that's to be used as the sort key for the index.
cdk?
Type :
cdk.index?
Type : Omit<LocalSecondaryIndexProps, "indexName" | "sortKey">
Override the settings of the internally created local secondary indexes
TableGlobalIndexProps
partitionKey
Type : string
The field that's to be used as a partition key for the index.
projection?
Type : Array<string> | "all" | "keys_only"
Default : "all"
The set of attributes that are projected into the secondary index.
sortKey?
Type : string
The field that's to be used as the sort key for the index.
cdk?
Type :
cdk.index?
Type : Omit<GlobalSecondaryIndexProps, "indexName" | "sortKey" | "partitionKey">
Override the settings of the internally created global secondary index