DynamoDB Tables
Complete guide to DynamoDB table design, creation, and management
DynamoDB tables are the fundamental building blocks for storing data. Understanding table design is crucial for building performant and cost-effective applications.
Table Fundamentals
Key Concepts
- Table: Container for items (similar to rows in SQL)
- Item: A single data record with attributes
- Attribute: A data element (similar to columns)
- Primary Key: Unique identifier for each item
Primary Keys
Every table requires a primary key, which can be:
Simple primary key using only a partition key:
aws dynamodb create-table \
--table-name Users \
--attribute-definitions \
AttributeName=userId,AttributeType=S \
--key-schema \
AttributeName=userId,KeyType=HASH \
--billing-mode PAY_PER_REQUEST| Attribute | Key Type | Description |
|---|---|---|
userId | HASH (Partition) | Distributes data across partitions |
Use when:
- Each item has a unique identifier
- You always query by that identifier
- No need for range queries
Composite primary key using partition key + sort key:
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions \
AttributeName=customerId,AttributeType=S \
AttributeName=orderDate,AttributeType=S \
--key-schema \
AttributeName=customerId,KeyType=HASH \
AttributeName=orderDate,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST| Attribute | Key Type | Description |
|---|---|---|
customerId | HASH (Partition) | Groups items by customer |
orderDate | RANGE (Sort) | Orders items within partition |
Use when:
- Multiple items share the same partition key
- You need to query ranges (dates, IDs, etc.)
- Hierarchical data (parent-child relationships)
Attribute Types
| Type Code | Type | Example |
|---|---|---|
| S | String | "hello" |
| N | Number | 123, 3.14 |
| B | Binary | Base64-encoded |
| BOOL | Boolean | true, false |
| NULL | Null | null |
| L | List | ["a", 1, true] |
| M | Map | {"key": "value"} |
| SS | String Set | ["a", "b", "c"] |
| NS | Number Set | [1, 2, 3] |
| BS | Binary Set | Binary values |
Only partition key and sort key attributes need to be defined in AttributeDefinitions. Other attributes are schemaless.
Creating Tables
aws dynamodb create-table \
--table-name Products \
--attribute-definitions \
AttributeName=productId,AttributeType=S \
--key-schema \
AttributeName=productId,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--tags Key=Environment,Value=ProductionBenefits:
- Pay per request
- Automatic scaling
- No capacity planning
- Great for unpredictable workloads
aws dynamodb create-table \
--table-name Products \
--attribute-definitions \
AttributeName=productId,AttributeType=S \
--key-schema \
AttributeName=productId,KeyType=HASH \
--billing-mode PROVISIONED \
--provisioned-throughput \
ReadCapacityUnits=10,WriteCapacityUnits=5Benefits:
- Predictable costs
- Reserved capacity discounts
- Better for steady workloads
1 RCU = 1 strongly consistent read (4KB) per second 1 WCU = 1 write (1KB) per second
aws dynamodb create-table \
--table-name SecureTable \
--attribute-definitions \
AttributeName=id,AttributeType=S \
--key-schema \
AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--sse-specification \
Enabled=true,SSEType=KMS,KMSMasterKeyId=alias/my-keyEncryption options:
- AWS owned key (default, free)
- AWS managed key (aws/dynamodb)
- Customer managed key (your KMS key)
Table Classes
Choose the right table class for your access patterns:
| Class | Best For | Cost |
|---|---|---|
| Standard | Frequently accessed data | Higher storage, lower throughput |
| Standard-IA | Infrequently accessed data | 60% lower storage cost |
aws dynamodb create-table \
--table-name ArchiveTable \
--attribute-definitions \
AttributeName=id,AttributeType=S \
--key-schema \
AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--table-class STANDARD_INFREQUENT_ACCESSTime to Live (TTL)
Automatically delete expired items:
aws dynamodb update-time-to-live \
--table-name Sessions \
--time-to-live-specification \
Enabled=true,AttributeName=expirationTimeconst item = {
sessionId: { S: "abc123" },
userId: { S: "user-1" },
expirationTime: { N: String(Math.floor(Date.now() / 1000) + 3600) } // 1 hour
};TTL is eventually consistent. Items may persist up to 48 hours after expiration. Deletes don't consume WCUs.
Auto Scaling
Configure automatic capacity scaling:
aws application-autoscaling register-scalable-target \
--service-namespace dynamodb \
--resource-id "table/Products" \
--scalable-dimension dynamodb:table:ReadCapacityUnits \
--min-capacity 5 \
--max-capacity 100aws application-autoscaling put-scaling-policy \
--service-namespace dynamodb \
--resource-id "table/Products" \
--scalable-dimension dynamodb:table:ReadCapacityUnits \
--policy-name ProductsReadScaling \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "DynamoDBReadCapacityUtilization"
},
"ScaleInCooldown": 60,
"ScaleOutCooldown": 60
}'Managing Tables
aws dynamodb describe-table \
--table-name Products \
--query 'Table.{
Name: TableName,
Status: TableStatus,
ItemCount: ItemCount,
Size: TableSizeBytes,
Keys: KeySchema
}'aws dynamodb list-tablesaws dynamodb update-table \
--table-name Products \
--provisioned-throughput \
ReadCapacityUnits=20,WriteCapacityUnits=10aws dynamodb update-table \
--table-name Products \
--billing-mode PAY_PER_REQUESTaws dynamodb update-table \
--table-name Products \
--table-class STANDARD_INFREQUENT_ACCESSaws dynamodb delete-table --table-name ProductsDeleting a table is irreversible. All data is permanently lost. Consider enabling Point-in-Time Recovery before deletion.
Point-in-Time Recovery
Enable continuous backups:
aws dynamodb update-continuous-backups \
--table-name Products \
--point-in-time-recovery-specification \
PointInTimeRecoveryEnabled=trueaws dynamodb restore-table-to-point-in-time \
--source-table-name Products \
--target-table-name Products-Restored \
--restore-date-time 2024-01-15T10:30:00ZPITR retains 35 days of backups. You can restore to any second within that window.
On-Demand Backup
Create manual backups:
aws dynamodb create-backup \
--table-name Products \
--backup-name Products-2024-01-15aws dynamodb restore-table-from-backup \
--target-table-name Products-Restored \
--backup-arn arn:aws:dynamodb:us-east-1:123456789012:table/Products/backup/01234567890aws dynamodb list-backups \
--table-name ProductsTable Design Best Practices
Design for Access Patterns
Start with your queries, then design your table structure:
Access Pattern: Get orders for a customer in the last month
→ Partition Key: customerId
→ Sort Key: orderDateUse Composite Sort Keys
Combine multiple values in the sort key for flexible queries:
Sort Key: ORDER#2024-01-15#order123
→ Query by type: begins_with(sk, "ORDER#")
→ Query by date: begins_with(sk, "ORDER#2024-01")
→ Query specific: sk = "ORDER#2024-01-15#order123"Consider Single-Table Design
For related entities, use the same table with different key patterns:
PK | SK | Attributes
USER#123 | PROFILE | name, email, ...
USER#123 | ORDER#2024-01-15 | total, status, ...
USER#123 | ADDR#home | street, city, ...Distribute Partition Keys
Avoid hot partitions with high-cardinality keys:
Good: userId, orderId, productId
Bad: status (only a few values), date (sequential)
Table Metrics
Monitor table health:
aws cloudwatch get-metric-statistics \
--namespace AWS/DynamoDB \
--metric-name ConsumedReadCapacityUnits \
--dimensions Name=TableName,Value=Products \
--start-time $(date -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date +%Y-%m-%dT%H:%M:%SZ) \
--period 300 \
--statistics SumKey metrics:
- ConsumedReadCapacityUnits/ConsumedWriteCapacityUnits
- ThrottledRequests
- SuccessfulRequestLatency
- UserErrors/SystemErrors
Best Practices
Table Design Guidelines
- Design for access patterns first - Not normalized like SQL
- Use on-demand for variable workloads - Avoid capacity planning
- Enable PITR - Protection against data loss
- Use TTL - Automatic cleanup of expired data
- Monitor throttles - Set up CloudWatch alarms
- Consider Standard-IA - For infrequent access tables
- Tag tables - For cost allocation and organization
- Use consistent naming - Environment, application prefixes