DynamoDB Table Auto Scaling Enabled
Overview
This check verifies that DynamoDB tables can automatically scale their read and write capacity based on demand. Tables should use either on-demand capacity mode (which scales automatically) or provisioned capacity mode with auto scaling configured.
Risk
If DynamoDB tables cannot scale with demand, your applications may experience:
- Throttling: Requests get rejected when capacity limits are exceeded
- Degraded performance: Increased latency and timeouts
- Cascading failures: Retry storms and request backlogs
- Poor user experience: Application errors and slow response times
Remediation Steps
Prerequisites
You need permission to modify DynamoDB tables. Specifically, you need:
dynamodb:UpdateTablepermission- For auto scaling:
application-autoscaling:*permissions
Required IAM permissions (full list)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:UpdateTable",
"dynamodb:DescribeTable",
"application-autoscaling:RegisterScalableTarget",
"application-autoscaling:PutScalingPolicy",
"application-autoscaling:DescribeScalableTargets",
"application-autoscaling:DescribeScalingPolicies"
],
"Resource": "*"
}
]
}
Choose Your Approach
There are two ways to enable automatic scaling:
| Approach | Best For | Cost Model |
|---|---|---|
| On-demand mode | Variable/unpredictable traffic | Pay per request |
| Provisioned + Auto Scaling | Predictable traffic patterns | Pay for provisioned capacity |
Recommendation: If you are unsure which to choose, start with on-demand mode. It is simpler to set up and works well for most workloads.
Option 1: Enable On-Demand Mode (Recommended)
This is the simplest approach. DynamoDB automatically handles all capacity scaling.
AWS Console Method
- Open the DynamoDB console
- Select your table from the list
- Click the Additional settings tab
- In the Read/write capacity settings section, click Edit
- Under Capacity mode, select On-demand
- Click Save changes
The change takes effect immediately. Your table status will briefly show "Updating" and then return to "Active."
AWS CLI (optional)
aws dynamodb update-table \
--table-name <your-table-name> \
--billing-mode PAY_PER_REQUEST \
--region us-east-1
Replace <your-table-name> with your actual table name.
Example:
aws dynamodb update-table \
--table-name orders \
--billing-mode PAY_PER_REQUEST \
--region us-east-1
Option 2: Enable Provisioned Mode with Auto Scaling
Use this approach if you have predictable traffic and want more cost control.
AWS Console Method
- Open the DynamoDB console
- Select your table from the list
- Click the Additional settings tab
- In the Read/write capacity settings section, click Edit
- Under Capacity mode, select Provisioned
- For Read capacity, check Auto scaling
- Set Minimum capacity units (e.g., 5)
- Set Maximum capacity units (e.g., 100)
- Set Target utilization (e.g., 70%)
- For Write capacity, check Auto scaling
- Set the same parameters as read capacity
- Click Save changes
AWS CLI (optional)
Auto scaling with the CLI requires multiple commands. First, register scalable targets, then create scaling policies.
Step 1: Register scalable targets
# Register read capacity auto scaling
aws application-autoscaling register-scalable-target \
--service-namespace dynamodb \
--resource-id "table/<your-table-name>" \
--scalable-dimension "dynamodb:table:ReadCapacityUnits" \
--min-capacity 5 \
--max-capacity 100 \
--region us-east-1
# Register write capacity auto scaling
aws application-autoscaling register-scalable-target \
--service-namespace dynamodb \
--resource-id "table/<your-table-name>" \
--scalable-dimension "dynamodb:table:WriteCapacityUnits" \
--min-capacity 5 \
--max-capacity 100 \
--region us-east-1
Step 2: Create scaling policies
# Create read capacity scaling policy
aws application-autoscaling put-scaling-policy \
--service-namespace dynamodb \
--resource-id "table/<your-table-name>" \
--scalable-dimension "dynamodb:table:ReadCapacityUnits" \
--policy-name "DynamoDBReadAutoScalingPolicy" \
--policy-type "TargetTrackingScaling" \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "DynamoDBReadCapacityUtilization"
}
}' \
--region us-east-1
# Create write capacity scaling policy
aws application-autoscaling put-scaling-policy \
--service-namespace dynamodb \
--resource-id "table/<your-table-name>" \
--scalable-dimension "dynamodb:table:WriteCapacityUnits" \
--policy-name "DynamoDBWriteAutoScalingPolicy" \
--policy-type "TargetTrackingScaling" \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "DynamoDBWriteCapacityUtilization"
}
}' \
--region us-east-1
Replace <your-table-name> with your actual table name.
CloudFormation (optional)
On-demand mode (simple):
AWSTemplateFormatVersion: '2010-09-09'
Description: DynamoDB table with on-demand capacity mode
Resources:
DynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: my-table
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: pk
AttributeType: S
KeySchema:
- AttributeName: pk
KeyType: HASH
Tags:
- Key: Environment
Value: Production
Provisioned mode with auto scaling:
AWSTemplateFormatVersion: '2010-09-09'
Description: DynamoDB table with provisioned capacity and auto scaling
Resources:
DynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: my-table
BillingMode: PROVISIONED
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
AttributeDefinitions:
- AttributeName: pk
AttributeType: S
KeySchema:
- AttributeName: pk
KeyType: HASH
WriteScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MaxCapacity: 100
MinCapacity: 5
ResourceId: !Sub table/${DynamoDBTable}
RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable
ScalableDimension: dynamodb:table:WriteCapacityUnits
ServiceNamespace: dynamodb
ReadScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
Properties:
MaxCapacity: 100
MinCapacity: 5
ResourceId: !Sub table/${DynamoDBTable}
RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable
ScalableDimension: dynamodb:table:ReadCapacityUnits
ServiceNamespace: dynamodb
WriteScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: WriteAutoScalingPolicy
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref WriteScalableTarget
TargetTrackingScalingPolicyConfiguration:
TargetValue: 70.0
PredefinedMetricSpecification:
PredefinedMetricType: DynamoDBWriteCapacityUtilization
ReadScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
Properties:
PolicyName: ReadAutoScalingPolicy
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref ReadScalableTarget
TargetTrackingScalingPolicyConfiguration:
TargetValue: 70.0
PredefinedMetricSpecification:
PredefinedMetricType: DynamoDBReadCapacityUtilization
Terraform (optional)
On-demand mode (simple):
resource "aws_dynamodb_table" "example" {
name = "my-table"
billing_mode = "PAY_PER_REQUEST"
hash_key = "pk"
attribute {
name = "pk"
type = "S"
}
tags = {
Environment = "Production"
}
}
Provisioned mode with auto scaling:
resource "aws_dynamodb_table" "example" {
name = "my-table"
billing_mode = "PROVISIONED"
read_capacity = 5
write_capacity = 5
hash_key = "pk"
attribute {
name = "pk"
type = "S"
}
tags = {
Environment = "Production"
}
}
# Auto scaling for read capacity
resource "aws_appautoscaling_target" "read_target" {
max_capacity = 100
min_capacity = 5
resource_id = "table/${aws_dynamodb_table.example.name}"
scalable_dimension = "dynamodb:table:ReadCapacityUnits"
service_namespace = "dynamodb"
}
resource "aws_appautoscaling_policy" "read_policy" {
name = "DynamoDBReadAutoScalingPolicy"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.read_target.resource_id
scalable_dimension = aws_appautoscaling_target.read_target.scalable_dimension
service_namespace = aws_appautoscaling_target.read_target.service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "DynamoDBReadCapacityUtilization"
}
target_value = 70.0
}
}
# Auto scaling for write capacity
resource "aws_appautoscaling_target" "write_target" {
max_capacity = 100
min_capacity = 5
resource_id = "table/${aws_dynamodb_table.example.name}"
scalable_dimension = "dynamodb:table:WriteCapacityUnits"
service_namespace = "dynamodb"
}
resource "aws_appautoscaling_policy" "write_policy" {
name = "DynamoDBWriteAutoScalingPolicy"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.write_target.resource_id
scalable_dimension = aws_appautoscaling_target.write_target.scalable_dimension
service_namespace = aws_appautoscaling_target.write_target.service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "DynamoDBWriteCapacityUtilization"
}
target_value = 70.0
}
}
Verification
After making changes, verify that auto scaling is properly configured:
- Open the DynamoDB console
- Select your table
- Click the Additional settings tab
- Check the Read/write capacity settings section:
- For on-demand: Should show "On-demand" as the capacity mode
- For provisioned: Should show "Auto scaling" enabled for both read and write capacity
CLI verification commands
Check table billing mode:
aws dynamodb describe-table \
--table-name <your-table-name> \
--query "Table.BillingModeSummary.BillingMode" \
--region us-east-1
Expected output for on-demand: "PAY_PER_REQUEST"
Check auto scaling targets (for provisioned mode):
aws application-autoscaling describe-scalable-targets \
--service-namespace dynamodb \
--resource-ids "table/<your-table-name>" \
--region us-east-1
You should see entries for both ReadCapacityUnits and WriteCapacityUnits.
Additional Resources
- DynamoDB Auto Scaling
- DynamoDB Read/Write Capacity Mode
- Application Auto Scaling for DynamoDB
- Prowler Check Documentation
Notes
- Switching modes: You can switch between on-demand and provisioned modes, but there is a 24-hour cooldown period between switches in the same direction.
- Global Secondary Indexes (GSIs): If your table has GSIs, they inherit the billing mode from the main table. For provisioned mode with auto scaling, you need to configure auto scaling separately for each GSI.
- Cost considerations: On-demand mode is more expensive per request but simpler to manage. Provisioned mode with auto scaling can be more cost-effective for predictable workloads.
- Scale-in cooldown: Auto scaling has a default 5-minute cooldown for scale-in actions to prevent rapid scaling fluctuations.