The aws:dynamodb/table:Table resource, part of the Pulumi AWS provider, defines a DynamoDB table’s structure: its primary keys, attributes, indexes, and optional multi-region replication. This guide focuses on three capabilities: primary key and index configuration, multi-region replication, and strong consistency modes.
DynamoDB tables require attribute definitions for keys and indexes. Global tables require AWS provider configuration for each replica region. The examples are intentionally small. Combine them with your own capacity planning, encryption, and backup configuration.
Define a table with hash key and global secondary index
Most deployments start with a single-region table that defines a primary key structure and optional secondary indexes for alternate query patterns.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const basic_dynamodb_table = new aws.dynamodb.Table("basic-dynamodb-table", {
name: "GameScores",
billingMode: "PROVISIONED",
readCapacity: 20,
writeCapacity: 20,
hashKey: "UserId",
rangeKey: "GameTitle",
attributes: [
{
name: "UserId",
type: "S",
},
{
name: "GameTitle",
type: "S",
},
{
name: "TopScore",
type: "N",
},
],
ttl: {
attributeName: "TimeToExist",
enabled: true,
},
globalSecondaryIndexes: [{
name: "GameTitleIndex",
hashKey: "GameTitle",
rangeKey: "TopScore",
writeCapacity: 10,
readCapacity: 10,
projectionType: "INCLUDE",
nonKeyAttributes: ["UserId"],
}],
tags: {
Name: "dynamodb-table-1",
Environment: "production",
},
});
import pulumi
import pulumi_aws as aws
basic_dynamodb_table = aws.dynamodb.Table("basic-dynamodb-table",
name="GameScores",
billing_mode="PROVISIONED",
read_capacity=20,
write_capacity=20,
hash_key="UserId",
range_key="GameTitle",
attributes=[
{
"name": "UserId",
"type": "S",
},
{
"name": "GameTitle",
"type": "S",
},
{
"name": "TopScore",
"type": "N",
},
],
ttl={
"attribute_name": "TimeToExist",
"enabled": True,
},
global_secondary_indexes=[{
"name": "GameTitleIndex",
"hash_key": "GameTitle",
"range_key": "TopScore",
"write_capacity": 10,
"read_capacity": 10,
"projection_type": "INCLUDE",
"non_key_attributes": ["UserId"],
}],
tags={
"Name": "dynamodb-table-1",
"Environment": "production",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/dynamodb"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := dynamodb.NewTable(ctx, "basic-dynamodb-table", &dynamodb.TableArgs{
Name: pulumi.String("GameScores"),
BillingMode: pulumi.String("PROVISIONED"),
ReadCapacity: pulumi.Int(20),
WriteCapacity: pulumi.Int(20),
HashKey: pulumi.String("UserId"),
RangeKey: pulumi.String("GameTitle"),
Attributes: dynamodb.TableAttributeArray{
&dynamodb.TableAttributeArgs{
Name: pulumi.String("UserId"),
Type: pulumi.String("S"),
},
&dynamodb.TableAttributeArgs{
Name: pulumi.String("GameTitle"),
Type: pulumi.String("S"),
},
&dynamodb.TableAttributeArgs{
Name: pulumi.String("TopScore"),
Type: pulumi.String("N"),
},
},
Ttl: &dynamodb.TableTtlArgs{
AttributeName: pulumi.String("TimeToExist"),
Enabled: pulumi.Bool(true),
},
GlobalSecondaryIndexes: dynamodb.TableGlobalSecondaryIndexArray{
&dynamodb.TableGlobalSecondaryIndexArgs{
Name: pulumi.String("GameTitleIndex"),
HashKey: pulumi.String("GameTitle"),
RangeKey: pulumi.String("TopScore"),
WriteCapacity: pulumi.Int(10),
ReadCapacity: pulumi.Int(10),
ProjectionType: pulumi.String("INCLUDE"),
NonKeyAttributes: pulumi.StringArray{
pulumi.String("UserId"),
},
},
},
Tags: pulumi.StringMap{
"Name": pulumi.String("dynamodb-table-1"),
"Environment": pulumi.String("production"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var basic_dynamodb_table = new Aws.DynamoDB.Table("basic-dynamodb-table", new()
{
Name = "GameScores",
BillingMode = "PROVISIONED",
ReadCapacity = 20,
WriteCapacity = 20,
HashKey = "UserId",
RangeKey = "GameTitle",
Attributes = new[]
{
new Aws.DynamoDB.Inputs.TableAttributeArgs
{
Name = "UserId",
Type = "S",
},
new Aws.DynamoDB.Inputs.TableAttributeArgs
{
Name = "GameTitle",
Type = "S",
},
new Aws.DynamoDB.Inputs.TableAttributeArgs
{
Name = "TopScore",
Type = "N",
},
},
Ttl = new Aws.DynamoDB.Inputs.TableTtlArgs
{
AttributeName = "TimeToExist",
Enabled = true,
},
GlobalSecondaryIndexes = new[]
{
new Aws.DynamoDB.Inputs.TableGlobalSecondaryIndexArgs
{
Name = "GameTitleIndex",
HashKey = "GameTitle",
RangeKey = "TopScore",
WriteCapacity = 10,
ReadCapacity = 10,
ProjectionType = "INCLUDE",
NonKeyAttributes = new[]
{
"UserId",
},
},
},
Tags =
{
{ "Name", "dynamodb-table-1" },
{ "Environment", "production" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.dynamodb.Table;
import com.pulumi.aws.dynamodb.TableArgs;
import com.pulumi.aws.dynamodb.inputs.TableAttributeArgs;
import com.pulumi.aws.dynamodb.inputs.TableTtlArgs;
import com.pulumi.aws.dynamodb.inputs.TableGlobalSecondaryIndexArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var basic_dynamodb_table = new Table("basic-dynamodb-table", TableArgs.builder()
.name("GameScores")
.billingMode("PROVISIONED")
.readCapacity(20)
.writeCapacity(20)
.hashKey("UserId")
.rangeKey("GameTitle")
.attributes(
TableAttributeArgs.builder()
.name("UserId")
.type("S")
.build(),
TableAttributeArgs.builder()
.name("GameTitle")
.type("S")
.build(),
TableAttributeArgs.builder()
.name("TopScore")
.type("N")
.build())
.ttl(TableTtlArgs.builder()
.attributeName("TimeToExist")
.enabled(true)
.build())
.globalSecondaryIndexes(TableGlobalSecondaryIndexArgs.builder()
.name("GameTitleIndex")
.hashKey("GameTitle")
.rangeKey("TopScore")
.writeCapacity(10)
.readCapacity(10)
.projectionType("INCLUDE")
.nonKeyAttributes("UserId")
.build())
.tags(Map.ofEntries(
Map.entry("Name", "dynamodb-table-1"),
Map.entry("Environment", "production")
))
.build());
}
}
resources:
basic-dynamodb-table:
type: aws:dynamodb:Table
properties:
name: GameScores
billingMode: PROVISIONED
readCapacity: 20
writeCapacity: 20
hashKey: UserId
rangeKey: GameTitle
attributes:
- name: UserId
type: S
- name: GameTitle
type: S
- name: TopScore
type: N
ttl:
attributeName: TimeToExist
enabled: true
globalSecondaryIndexes:
- name: GameTitleIndex
hashKey: GameTitle
rangeKey: TopScore
writeCapacity: 10
readCapacity: 10
projectionType: INCLUDE
nonKeyAttributes:
- UserId
tags:
Name: dynamodb-table-1
Environment: production
The hashKey and rangeKey properties define the primary key structure (partition key and sort key). Every attribute used in keys or indexes must appear in the attributes array with its name and type. The globalSecondaryIndexes block creates alternate query patterns; here, GameTitleIndex lets you query by game title and top score instead of user ID. The billingMode controls whether you pay per request or provision fixed capacity.
Replicate tables across multiple regions
Applications serving global users often replicate tables to multiple regions for low-latency access and disaster recovery.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.dynamodb.Table("example", {
name: "example",
hashKey: "TestTableHashKey",
billingMode: "PAY_PER_REQUEST",
streamEnabled: true,
streamViewType: "NEW_AND_OLD_IMAGES",
attributes: [{
name: "TestTableHashKey",
type: "S",
}],
replicas: [
{
regionName: "us-east-2",
},
{
regionName: "us-west-2",
},
],
});
import pulumi
import pulumi_aws as aws
example = aws.dynamodb.Table("example",
name="example",
hash_key="TestTableHashKey",
billing_mode="PAY_PER_REQUEST",
stream_enabled=True,
stream_view_type="NEW_AND_OLD_IMAGES",
attributes=[{
"name": "TestTableHashKey",
"type": "S",
}],
replicas=[
{
"region_name": "us-east-2",
},
{
"region_name": "us-west-2",
},
])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/dynamodb"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := dynamodb.NewTable(ctx, "example", &dynamodb.TableArgs{
Name: pulumi.String("example"),
HashKey: pulumi.String("TestTableHashKey"),
BillingMode: pulumi.String("PAY_PER_REQUEST"),
StreamEnabled: pulumi.Bool(true),
StreamViewType: pulumi.String("NEW_AND_OLD_IMAGES"),
Attributes: dynamodb.TableAttributeArray{
&dynamodb.TableAttributeArgs{
Name: pulumi.String("TestTableHashKey"),
Type: pulumi.String("S"),
},
},
Replicas: dynamodb.TableReplicaTypeArray{
&dynamodb.TableReplicaTypeArgs{
RegionName: pulumi.String("us-east-2"),
},
&dynamodb.TableReplicaTypeArgs{
RegionName: pulumi.String("us-west-2"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.DynamoDB.Table("example", new()
{
Name = "example",
HashKey = "TestTableHashKey",
BillingMode = "PAY_PER_REQUEST",
StreamEnabled = true,
StreamViewType = "NEW_AND_OLD_IMAGES",
Attributes = new[]
{
new Aws.DynamoDB.Inputs.TableAttributeArgs
{
Name = "TestTableHashKey",
Type = "S",
},
},
Replicas = new[]
{
new Aws.DynamoDB.Inputs.TableReplicaArgs
{
RegionName = "us-east-2",
},
new Aws.DynamoDB.Inputs.TableReplicaArgs
{
RegionName = "us-west-2",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.dynamodb.Table;
import com.pulumi.aws.dynamodb.TableArgs;
import com.pulumi.aws.dynamodb.inputs.TableAttributeArgs;
import com.pulumi.aws.dynamodb.inputs.TableReplicaArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Table("example", TableArgs.builder()
.name("example")
.hashKey("TestTableHashKey")
.billingMode("PAY_PER_REQUEST")
.streamEnabled(true)
.streamViewType("NEW_AND_OLD_IMAGES")
.attributes(TableAttributeArgs.builder()
.name("TestTableHashKey")
.type("S")
.build())
.replicas(
TableReplicaArgs.builder()
.regionName("us-east-2")
.build(),
TableReplicaArgs.builder()
.regionName("us-west-2")
.build())
.build());
}
}
resources:
example:
type: aws:dynamodb:Table
properties:
name: example
hashKey: TestTableHashKey
billingMode: PAY_PER_REQUEST
streamEnabled: true
streamViewType: NEW_AND_OLD_IMAGES
attributes:
- name: TestTableHashKey
type: S
replicas:
- regionName: us-east-2
- regionName: us-west-2
The replicas array defines target regions for replication. DynamoDB automatically synchronizes writes across all replicas with eventual consistency. The streamEnabled and streamViewType properties are required for replication; they capture change events that DynamoDB uses to propagate updates. Each replica maintains its own copy of the data.
Enable strong consistency across three regions
Some applications require strongly consistent reads across regions, ensuring every read returns the most recent write regardless of which region handles the request.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.dynamodb.Table("example", {
name: "example",
hashKey: "TestTableHashKey",
billingMode: "PAY_PER_REQUEST",
streamEnabled: true,
streamViewType: "NEW_AND_OLD_IMAGES",
attributes: [{
name: "TestTableHashKey",
type: "S",
}],
replicas: [
{
regionName: "us-east-2",
consistencyMode: "STRONG",
},
{
regionName: "us-west-2",
consistencyMode: "STRONG",
},
],
});
import pulumi
import pulumi_aws as aws
example = aws.dynamodb.Table("example",
name="example",
hash_key="TestTableHashKey",
billing_mode="PAY_PER_REQUEST",
stream_enabled=True,
stream_view_type="NEW_AND_OLD_IMAGES",
attributes=[{
"name": "TestTableHashKey",
"type": "S",
}],
replicas=[
{
"region_name": "us-east-2",
"consistency_mode": "STRONG",
},
{
"region_name": "us-west-2",
"consistency_mode": "STRONG",
},
])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/dynamodb"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := dynamodb.NewTable(ctx, "example", &dynamodb.TableArgs{
Name: pulumi.String("example"),
HashKey: pulumi.String("TestTableHashKey"),
BillingMode: pulumi.String("PAY_PER_REQUEST"),
StreamEnabled: pulumi.Bool(true),
StreamViewType: pulumi.String("NEW_AND_OLD_IMAGES"),
Attributes: dynamodb.TableAttributeArray{
&dynamodb.TableAttributeArgs{
Name: pulumi.String("TestTableHashKey"),
Type: pulumi.String("S"),
},
},
Replicas: dynamodb.TableReplicaTypeArray{
&dynamodb.TableReplicaTypeArgs{
RegionName: pulumi.String("us-east-2"),
ConsistencyMode: pulumi.String("STRONG"),
},
&dynamodb.TableReplicaTypeArgs{
RegionName: pulumi.String("us-west-2"),
ConsistencyMode: pulumi.String("STRONG"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.DynamoDB.Table("example", new()
{
Name = "example",
HashKey = "TestTableHashKey",
BillingMode = "PAY_PER_REQUEST",
StreamEnabled = true,
StreamViewType = "NEW_AND_OLD_IMAGES",
Attributes = new[]
{
new Aws.DynamoDB.Inputs.TableAttributeArgs
{
Name = "TestTableHashKey",
Type = "S",
},
},
Replicas = new[]
{
new Aws.DynamoDB.Inputs.TableReplicaArgs
{
RegionName = "us-east-2",
ConsistencyMode = "STRONG",
},
new Aws.DynamoDB.Inputs.TableReplicaArgs
{
RegionName = "us-west-2",
ConsistencyMode = "STRONG",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.dynamodb.Table;
import com.pulumi.aws.dynamodb.TableArgs;
import com.pulumi.aws.dynamodb.inputs.TableAttributeArgs;
import com.pulumi.aws.dynamodb.inputs.TableReplicaArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Table("example", TableArgs.builder()
.name("example")
.hashKey("TestTableHashKey")
.billingMode("PAY_PER_REQUEST")
.streamEnabled(true)
.streamViewType("NEW_AND_OLD_IMAGES")
.attributes(TableAttributeArgs.builder()
.name("TestTableHashKey")
.type("S")
.build())
.replicas(
TableReplicaArgs.builder()
.regionName("us-east-2")
.consistencyMode("STRONG")
.build(),
TableReplicaArgs.builder()
.regionName("us-west-2")
.consistencyMode("STRONG")
.build())
.build());
}
}
resources:
example:
type: aws:dynamodb:Table
properties:
name: example
hashKey: TestTableHashKey
billingMode: PAY_PER_REQUEST
streamEnabled: true
streamViewType: NEW_AND_OLD_IMAGES
attributes:
- name: TestTableHashKey
type: S
replicas:
- regionName: us-east-2
consistencyMode: STRONG
- regionName: us-west-2
consistencyMode: STRONG
Setting consistencyMode to STRONG on each replica enables multi-region strong consistency. This guarantees that reads in any replica region return the latest data, at the cost of higher latency compared to eventual consistency. You need at least three replicas for this configuration.
Use a witness region for two-replica strong consistency
When you need strong consistency but want to minimize full replica costs, a witness region provides the consistency guarantees without supporting read or write operations.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.dynamodb.Table("example", {
name: "example",
hashKey: "TestTableHashKey",
billingMode: "PAY_PER_REQUEST",
streamEnabled: true,
streamViewType: "NEW_AND_OLD_IMAGES",
attributes: [{
name: "TestTableHashKey",
type: "S",
}],
replicas: [{
regionName: "us-east-2",
consistencyMode: "STRONG",
}],
globalTableWitness: {
regionName: "us-west-2",
},
});
import pulumi
import pulumi_aws as aws
example = aws.dynamodb.Table("example",
name="example",
hash_key="TestTableHashKey",
billing_mode="PAY_PER_REQUEST",
stream_enabled=True,
stream_view_type="NEW_AND_OLD_IMAGES",
attributes=[{
"name": "TestTableHashKey",
"type": "S",
}],
replicas=[{
"region_name": "us-east-2",
"consistency_mode": "STRONG",
}],
global_table_witness={
"region_name": "us-west-2",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/dynamodb"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := dynamodb.NewTable(ctx, "example", &dynamodb.TableArgs{
Name: pulumi.String("example"),
HashKey: pulumi.String("TestTableHashKey"),
BillingMode: pulumi.String("PAY_PER_REQUEST"),
StreamEnabled: pulumi.Bool(true),
StreamViewType: pulumi.String("NEW_AND_OLD_IMAGES"),
Attributes: dynamodb.TableAttributeArray{
&dynamodb.TableAttributeArgs{
Name: pulumi.String("TestTableHashKey"),
Type: pulumi.String("S"),
},
},
Replicas: dynamodb.TableReplicaTypeArray{
&dynamodb.TableReplicaTypeArgs{
RegionName: pulumi.String("us-east-2"),
ConsistencyMode: pulumi.String("STRONG"),
},
},
GlobalTableWitness: &dynamodb.TableGlobalTableWitnessArgs{
RegionName: pulumi.String("us-west-2"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.DynamoDB.Table("example", new()
{
Name = "example",
HashKey = "TestTableHashKey",
BillingMode = "PAY_PER_REQUEST",
StreamEnabled = true,
StreamViewType = "NEW_AND_OLD_IMAGES",
Attributes = new[]
{
new Aws.DynamoDB.Inputs.TableAttributeArgs
{
Name = "TestTableHashKey",
Type = "S",
},
},
Replicas = new[]
{
new Aws.DynamoDB.Inputs.TableReplicaArgs
{
RegionName = "us-east-2",
ConsistencyMode = "STRONG",
},
},
GlobalTableWitness = new Aws.DynamoDB.Inputs.TableGlobalTableWitnessArgs
{
RegionName = "us-west-2",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.dynamodb.Table;
import com.pulumi.aws.dynamodb.TableArgs;
import com.pulumi.aws.dynamodb.inputs.TableAttributeArgs;
import com.pulumi.aws.dynamodb.inputs.TableReplicaArgs;
import com.pulumi.aws.dynamodb.inputs.TableGlobalTableWitnessArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new Table("example", TableArgs.builder()
.name("example")
.hashKey("TestTableHashKey")
.billingMode("PAY_PER_REQUEST")
.streamEnabled(true)
.streamViewType("NEW_AND_OLD_IMAGES")
.attributes(TableAttributeArgs.builder()
.name("TestTableHashKey")
.type("S")
.build())
.replicas(TableReplicaArgs.builder()
.regionName("us-east-2")
.consistencyMode("STRONG")
.build())
.globalTableWitness(TableGlobalTableWitnessArgs.builder()
.regionName("us-west-2")
.build())
.build());
}
}
resources:
example:
type: aws:dynamodb:Table
properties:
name: example
hashKey: TestTableHashKey
billingMode: PAY_PER_REQUEST
streamEnabled: true
streamViewType: NEW_AND_OLD_IMAGES
attributes:
- name: TestTableHashKey
type: S
replicas:
- regionName: us-east-2
consistencyMode: STRONG
globalTableWitness:
regionName: us-west-2
The globalTableWitness property designates a region that participates in consistency protocols but doesn’t store a full copy of the data or handle requests. This reduces costs compared to three full replicas while maintaining strong consistency between the two active replicas. The witness region must differ from both replica regions.
Beyond these examples
These snippets focus on specific table-level features: single-region and multi-region table configuration, global secondary indexes, and strong consistency modes and witness regions. They’re intentionally minimal rather than full database deployments.
The examples may reference pre-existing infrastructure such as AWS provider configured for target regions. They focus on configuring the table rather than provisioning everything around it.
To keep things focused, common table patterns are omitted, including:
- Point-in-time recovery (pointInTimeRecovery)
- Server-side encryption with customer-managed keys (serverSideEncryption)
- Time-to-live expiration (ttl)
- Local secondary indexes (localSecondaryIndexes)
- Capacity planning (readCapacity, writeCapacity, onDemandThroughput)
- Table restoration from backups (restoreSourceName, restoreDateTime)
These omissions are intentional: the goal is to illustrate how each table feature is wired, not provide drop-in database modules. See the DynamoDB Table resource reference for all available configuration options.
Let's create and Configure DynamoDB Tables
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Attributes & Schema Design
attributes block if they’re used as the table’s hashKey or rangeKey, or as hash/range keys in GSIs or LSIs. Adding unused attributes causes infinite planning loops.hashKey and rangeKey, plus any attributes used as hash or range keys in Global Secondary Indexes (GSIs) or Local Secondary Indexes (LSIs). Don’t define other attributes even if they exist in your data.Capacity & Billing
PROVISIONED (default) requires you to specify readCapacity and writeCapacity values. PAY_PER_REQUEST automatically scales and doesn’t require capacity settings. Choose PAY_PER_REQUEST for unpredictable workloads or PROVISIONED for steady, predictable traffic.ignoreChanges for readCapacity and writeCapacity when you have an autoscaling policy attached. This prevents Pulumi from trying to manage capacity values that autoscaling controls dynamically.Global Tables & Replication
replica configuration blocks together with the aws.dynamodb.TableReplica resource, as they conflict. Pick the approach that fits your infrastructure organization.globalTableWitness with a region name alongside exactly one replica that has consistencyMode set to STRONG. Other combinations (multiple replicas, missing STRONG mode, or no replica) will fail to provision.replica configuration blocks. For Global Tables V1 (version 2017.11.29), use the separate aws.dynamodb.GlobalTable resource instead.propagateTags to true on individual replicas to inherit tags from the main table, or use the aws.dynamodb.Tag resource to manage replica tags independently in each region.Immutability & Lifecycle
name, hashKey, rangeKey, and localSecondaryIndexes. LSIs can only be allocated at table creation. If you need to change these, you must recreate the table.aws.dynamodb.TableReplica resource, add ignoreChanges for the replica property to prevent conflicts between the inline configuration and the separate resource managing the same replicas.Encryption & Cross-Region
serverSideEncryption configuration for cross-region restores. Otherwise, DynamoDB tables are automatically encrypted at rest with an AWS-owned Customer Master Key if you don’t specify this argument.