dynobase-icon
Dynobase

DynamoDB AWS CDK: TableV2, Indexes and Replicas

Chameera Dulanga

Written by Chameera Dulanga

Last updated: October 23rd, 2026

Writing DynamoDB code by hand? Dynobase turns supported data operations into application code or scripts, and generates CDK, CloudFormation or Terraform for an existing table. Code generation in Dynobase

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?

AWS recommends 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?

Set 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?

Yes. Current TableV2 exposes pointInTimeRecoverySpecification with a recovery period and warmThroughput. PITR and proactive pre-warming can incur charges.

Does a table grant configure my Lambda SDK client?

No. Grant methods configure IAM permissions. Pass the table name to the function and use the correct Region in the SDK client separately.

Dynobase is a Professional GUI Client for DynamoDB

Start your 7-day free trial today

Product Features

Download
/
Changelog
/
Pricing
/
Member Portal
/
Privacy
/
EULA
/
Twitter
© 2026 Dynobase