Skip to content

DynamoDB Table Construct

The DynamoDbTableConstruct provides a comprehensive, production-ready DynamoDB table with support for global secondary indexes, streams, TTL, and Lambda integration.

📊 Features

  • 🔑 Flexible Key Schema: Support for partition keys, sort keys, and composite keys
  • 🫵 Global Secondary Indexes: Multiple GSIs with custom key schemas
  • 🌊 DynamoDB Streams: Real-time data processing with Lambda integration
  • ⌛ TTL Support: Automatic data expiration
  • 📤 CloudFormation Outputs: Automatic exports for table ARN, name, and stream ARN
  • âš¡ Lambda Integration: Built-in method for attaching Lambda functions to streams
  • 💳 Billing Modes: Support for both PAY_PER_REQUEST and PROVISIONED billing

Basic Usage

using Amazon.CDK;
using LayeredCraft.Cdk.Constructs;
using LayeredCraft.Cdk.Constructs.Models;

public class MyStack : Stack
{
    public MyStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
    {
        var table = new DynamoDbTableConstruct(this, "MyTable", new DynamoDbTableConstructProps
        {
            TableName = "users",
            PartitionKey = new AttributeDefinition { AttributeName = "userId", AttributeType = AttributeType.STRING }
        });
    }
}

Configuration Properties

Required Properties

Property Type Description
TableName string Name of the DynamoDB table
PartitionKey AttributeDefinition Primary partition key definition

Optional Properties

Property Type Default Description
SortKey AttributeDefinition? null Primary sort key definition
GlobalSecondaryIndexes GlobalSecondaryIndex[] [] GSI definitions
StreamSpecification StreamViewType? null DynamoDB stream configuration
TimeToLiveAttribute string? null TTL attribute name
BillingMode BillingMode PAY_PER_REQUEST Table billing mode

Advanced Examples

Table with Sort Key

var table = new DynamoDbTableConstruct(this, "MyTable", new DynamoDbTableConstructProps
{
    TableName = "user-sessions",
    PartitionKey = new AttributeDefinition { AttributeName = "userId", AttributeType = AttributeType.STRING },
    SortKey = new AttributeDefinition { AttributeName = "sessionId", AttributeType = AttributeType.STRING }
});

Table with Global Secondary Index

var gsi = new GlobalSecondaryIndex
{
    IndexName = "email-index",
    PartitionKey = new AttributeDefinition { AttributeName = "email", AttributeType = AttributeType.STRING },
    ProjectionType = ProjectionType.ALL
};

var table = new DynamoDbTableConstruct(this, "MyTable", new DynamoDbTableConstructProps
{
    TableName = "users",
    PartitionKey = new AttributeDefinition { AttributeName = "userId", AttributeType = AttributeType.STRING },
    GlobalSecondaryIndexes = [gsi]
});

Table with DynamoDB Streams

var table = new DynamoDbTableConstruct(this, "MyTable", new DynamoDbTableConstructProps
{
    TableName = "events",
    PartitionKey = new AttributeDefinition { AttributeName = "eventId", AttributeType = AttributeType.STRING },
    StreamSpecification = StreamViewType.NEW_AND_OLD_IMAGES
});

Table with TTL

var table = new DynamoDbTableConstruct(this, "MyTable", new DynamoDbTableConstructProps
{
    TableName = "sessions",
    PartitionKey = new AttributeDefinition { AttributeName = "sessionId", AttributeType = AttributeType.STRING },
    TimeToLiveAttribute = "expiresAt" // Unix timestamp field
});

Complete Configuration

var emailGsi = new GlobalSecondaryIndex
{
    IndexName = "email-index",
    PartitionKey = new AttributeDefinition { AttributeName = "email", AttributeType = AttributeType.STRING },
    ProjectionType = ProjectionType.ALL
};

var statusGsi = new GlobalSecondaryIndex
{
    IndexName = "status-index",
    PartitionKey = new AttributeDefinition { AttributeName = "status", AttributeType = AttributeType.STRING },
    SortKey = new AttributeDefinition { AttributeName = "createdAt", AttributeType = AttributeType.NUMBER },
    ProjectionType = ProjectionType.KEYS_ONLY
};

var table = new DynamoDbTableConstruct(this, "MyTable", new DynamoDbTableConstructProps
{
    TableName = "users",
    PartitionKey = new AttributeDefinition { AttributeName = "userId", AttributeType = AttributeType.STRING },
    SortKey = new AttributeDefinition { AttributeName = "createdAt", AttributeType = AttributeType.NUMBER },
    GlobalSecondaryIndexes = [emailGsi, statusGsi],
    StreamSpecification = StreamViewType.NEW_AND_OLD_IMAGES,
    TimeToLiveAttribute = "expiresAt"
});

Lambda Stream Integration

The construct provides a convenient method to attach Lambda functions to DynamoDB streams:

var table = new DynamoDbTableConstruct(this, "MyTable", new DynamoDbTableConstructProps
{
    TableName = "events",
    PartitionKey = new AttributeDefinition { AttributeName = "eventId", AttributeType = AttributeType.STRING },
    StreamSpecification = StreamViewType.NEW_AND_OLD_IMAGES
});

// Create a Lambda function to process stream events
var streamProcessor = new LambdaFunctionConstruct(this, "StreamProcessor", new LambdaFunctionConstructProps
{
    FunctionName = "stream-processor",
    FunctionSuffix = "prod",
    AssetPath = "./lambda-stream-processor.zip",
    RoleName = "stream-processor-role",
    PolicyName = "stream-processor-policy"
});

// Attach Lambda to the stream
table.AttachStreamLambda(streamProcessor.LambdaFunction);

CloudFormation Outputs

The construct automatically creates CloudFormation outputs:

var table = new DynamoDbTableConstruct(this, "MyTable", props);

// Outputs created:
// - {StackName}-MyTable-table-arn-output
// - {StackName}-MyTable-table-name-output
// - {StackName}-MyTable-table-stream-arn-output (if streams enabled)

Stream View Types

View Type Description
KEYS_ONLY Only key attributes of the modified item
NEW_IMAGE Entire item after modification
OLD_IMAGE Entire item before modification
NEW_AND_OLD_IMAGES Both new and old images of the item

Billing Modes

PAY_PER_REQUEST (Default)

  • No provisioned capacity required
  • Scales automatically based on demand
  • Pay only for actual read/write requests

PROVISIONED

  • Specify read and write capacity units
  • More predictable costs for steady workloads
  • Requires capacity planning
var table = new DynamoDbTableConstruct(this, "MyTable", new DynamoDbTableConstructProps
{
    TableName = "users",
    PartitionKey = new AttributeDefinition { AttributeName = "userId", AttributeType = AttributeType.STRING },
    BillingMode = BillingMode.PROVISIONED,
    // Note: Provisioned capacity configuration would be added in future versions
});

Global Secondary Index Configuration

Projection Types

Projection Type Description
ALL All attributes projected
KEYS_ONLY Only key attributes projected
INCLUDE Key attributes plus specified attributes

GSI Example with Projection

var gsi = new GlobalSecondaryIndex
{
    IndexName = "status-index",
    PartitionKey = new AttributeDefinition { AttributeName = "status", AttributeType = AttributeType.STRING },
    SortKey = new AttributeDefinition { AttributeName = "updatedAt", AttributeType = AttributeType.NUMBER },
    ProjectionType = ProjectionType.INCLUDE,
    NonKeyAttributes = ["name", "email"] // Only with INCLUDE projection
};

Common Use Cases

User Management Table

var userTable = new DynamoDbTableConstruct(this, "UserTable", new DynamoDbTableConstructProps
{
    TableName = "users",
    PartitionKey = new AttributeDefinition { AttributeName = "userId", AttributeType = AttributeType.STRING },
    GlobalSecondaryIndexes = [
        new GlobalSecondaryIndex
        {
            IndexName = "email-index",
            PartitionKey = new AttributeDefinition { AttributeName = "email", AttributeType = AttributeType.STRING },
            ProjectionType = ProjectionType.ALL
        }
    ]
});

Session Management Table

var sessionTable = new DynamoDbTableConstruct(this, "SessionTable", new DynamoDbTableConstructProps
{
    TableName = "sessions",
    PartitionKey = new AttributeDefinition { AttributeName = "sessionId", AttributeType = AttributeType.STRING },
    TimeToLiveAttribute = "expiresAt"
});

Event Sourcing Table

var eventTable = new DynamoDbTableConstruct(this, "EventTable", new DynamoDbTableConstructProps
{
    TableName = "events",
    PartitionKey = new AttributeDefinition { AttributeName = "aggregateId", AttributeType = AttributeType.STRING },
    SortKey = new AttributeDefinition { AttributeName = "timestamp", AttributeType = AttributeType.NUMBER },
    StreamSpecification = StreamViewType.NEW_AND_OLD_IMAGES
});

Testing

See the Testing Guide for comprehensive testing utilities and patterns specific to the DynamoDB Table construct.

Examples

For more real-world examples, see the Examples section.