DynamoDB AWS CDK: TableV2, Indexes and Replicas

Written by Chameera Dulanga
Last updated: October 23rd, 2026
Use TableV2 from aws-cdk-lib/aws-dynamodb to define DynamoDB tables in AWS CDK v2. It supports single-Region tables and global-table replicas, defaults to on-demand billing, and exposes indexes, backups, deletion protection and warm throughput. CDK synthesizes these declarations into CloudFormation before deployment.
Why use AWS CDK for DynamoDB?
CDK lets you define infrastructure in TypeScript, JavaScript, Python, Java, C# or Go and pass resource references directly into application constructs. A table name can become a Lambda environment variable, while grant methods generate IAM statements for the function's role. You still review and deploy a CloudFormation change set.
For TypeScript projects, install aws-cdk-lib and constructs. Do not install the old @aws-cdk/aws-dynamodb package: that belongs to CDK v1, which reached end of support on June 1, 2023. The CLI package is aws-cdk; its version numbering is separate from aws-cdk-lib.
The DynamoDB construct library recommends TableV2. It produces AWS::DynamoDB::GlobalTable even for a single Region. The older Table produces AWS::DynamoDB::Table; replacing its class in an existing application requires migration planning, not just an import edit.
Step 1: initialize a TypeScript CDK application
Use a current supported Node.js release, AWS CLI v2 and an AWS profile with deployment permissions. Check the target account before creating resources:
The app template creates a stack in lib and an entry point in bin. It avoids the unrelated SNS and SQS resources in the sample-app template. Install the generated dependencies and keep the lock file in version control. CDK's CLI is a deployment tool; the DynamoDB SDK is a separate dependency used by your running application.
Step 2: define a table with indexes, TTL and backups
Replace the generated stack body with this TypeScript example, preserving the class name expected by your entry point:
The table has a composite primary key: callers must supply both id and createdAt to get or delete an item. The ByOwner GSI supports querying an owner's notes by creation time. Ordinary fields such as note text do not need declarations in CDK. See TableV2's API reference for the full property and method list.
expiresAt must be a Number containing Unix epoch seconds. TTL deletion is asynchronous, typically within a few days; it cannot enforce immediate session invalidation. PITR retains restore points for 1 to 35 days and restores to a new table. A shorter recovery window does not reduce the PITR price.
Local secondary indexes and table class
To add a local secondary index before the table's first deployment, put this property in the constructor:
An LSI shares the table partition key and provides an alternate sort key. You cannot add one to an already-created table. GSIs can be added later, but deployment and backfill take time; wait until an index is active before directing queries to it.
tableClass: dynamodb.TableClass.STANDARD_INFREQUENT_ACCESS selects Standard-IA. It trades cheaper storage for more expensive reads and writes. Keep Standard for the example and make a table-class decision using the workload's storage and request costs.
Step 3: configure capacity and auto scaling
TableV2 uses billing, not the older construct's billingMode. To set best-effort on-demand throughput caps, replace the billing property:
Requests above these targets can be throttled. They are request-unit rates, not a hard monthly budget, and burst capacity can temporarily exceed a cap. GSIs have their own maximum throughput options.
For provisioned capacity, use Billing.provisioned. TableV2 supports fixed or autoscaled read capacity; its write capacity must use the autoscaled form:
These bounds are example workload settings. Provisioned GSIs also need capacity planning; TableV2 lets them inherit the table's settings or override them. For capacity-mode changes, review the construct's seedCapacity requirements and the synthesized template before deployment.
Scheduled scaling in existing Table constructs
Existing CDK v2 applications using the older Table can still use its scaling helpers, including a scheduled increase. This is a separate construct example, not code to call on the TableV2 above:
Review the schedule's time zone and configure write scaling separately. Leaving an elevated minimum in place keeps that capacity provisioned even after traffic falls.
Warm throughput
Current TableV2 supports pre-warming directly:
This prepares immediate throughput for an expected peak and may incur a one-time charge. It does not switch capacity mode or replace provisioned capacity management. Warm throughput propagates across global-table replicas, with charges in each Region. Keep this optional configuration out of small examples unless pre-warming is the task.
Step 4: create global tables
Set the stack's Region explicitly in bin/aws-cdk-dynamodb.ts:
Add replicas to the original TableV2 properties:
The stack Region already contains a replica, so do not list it again. TableV2 lets replicas inherit settings such as PITR and deletion protection or override them explicitly. This is different from assuming the DynamoDB service synchronizes every setting. Read capacities and table classes can differ by replica.
For multi-Region strong consistency, create a separate table without TTL or LSIs:
With the stack in us-east-1, this creates two data replicas and a witness. MRSC requires three Regions and does not support transactions, TTL or LSIs. The witness cannot serve requests. Choose the consistency model at creation; the global tables guide explains the application trade-offs.
The old Table.replicationTimeout property is not a TableV2 option. Check CloudFormation events when a replica operation is slow, rather than copying the older custom-resource timeout setting into this construct.
Step 5: choose encryption keys
Encryption at rest is always enabled. The default is an AWS owned key. To use the AWS managed DynamoDB key, set encryption: dynamodb.TableEncryptionV2.awsManagedKey().
For a customer managed key on a single-Region table:
For global tables, pass a second argument mapping each replica Region to its existing KMS key ARN. Create those keys in their respective Regions first. Retain and protect the keys with the data; a retained table becomes unusable if its encryption key is unavailable.
Step 6: grant application access and capture changes
Inside the stack, grant a Lambda function access to the table and pass its generated name to the handler:
Create lambda/reader/index.mjs and bundle the SDK v3 dependencies there before deployment. grantReadData, grantWriteData and grantReadWriteData cover their corresponding groups of data operations. For a single operation, use table.grant(reader, "dynamodb:GetItem"). A grant configures IAM; it does not choose a Region or table name in your SDK client. Use table.replica("us-west-2") when granting access to a specific replica.
For DynamoDB Streams, set dynamoStream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES, then attach a Lambda DynamoDB event source. Stream permissions and table read permissions are distinct. Consumers must tolerate duplicate processing.
Kinesis Data Streams is another change-capture destination, configured separately:
Each replica needs its own Kinesis destination configuration; the primary table's stream is not automatically inherited. Kinesis adds its own retention, consumer and pricing choices.
Step 7: synthesize, review and deploy
Bootstrap the deployment environment before its first CDK deployment. Review changes to keys, resource types, IAM and retention before approving a deployment. Changing a table's key schema is a data migration, not an in-place schema update.
Monitor throttles, consumed capacity and index backfill through CloudWatch and test PITR restoration. RemovalPolicy.RETAIN preserves the resource when CloudFormation removes it; deletion protection also blocks direct service deletion. Retained resources continue to incur charges and require explicit lifecycle management.
For local handler testing, point SDK v3 at DynamoDB Local. CDK itself deploys infrastructure to AWS. If you prefer to inspect YAML directly, use the CloudFormation examples; if your team owns infrastructure through HCL, compare the Terraform approach.
Frequently Asked Questions
Should I use Table or TableV2 in AWS CDK?
TableV2 for new single-Region and global tables. It creates a CloudFormation GlobalTable resource; migrating an existing Table construct needs a deliberate retention and import plan.How do I enable on-demand billing in TableV2?
billing: dynamodb.Billing.onDemand(), or leave billing unspecified because on-demand is the default. The older billingMode property belongs to Table.Can CDK configure DynamoDB backups and warm throughput?
pointInTimeRecoverySpecification with a recovery period and warmThroughput. PITR and proactive pre-warming can incur charges.Does a table grant configure my Lambda SDK client?
Dynobase is a Professional GUI Client for DynamoDB
Start your 7-day free trial today
Product Features
DynamoDB Tools
- SSH GUI Client
- Chat With Cloud
- MongoDB GUI Client
- AWS Cost Monitoring
- DynamoDB Query Builder
- DynamoDB Code Examples
- DynamoDB Node.js Queries
- DynamoDB JSON Converter
- DynamoDB UUID Generator
- DynamoDB Local Admin GUI
- DynamoDB Pricing Calculator
- DynamoDB Single-Table Design
- Best DynamoDB GUI Clients
- Dynobase vs DynoTable