Skip to main content

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:UpdateTable permission
  • 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:

ApproachBest ForCost Model
On-demand modeVariable/unpredictable trafficPay per request
Provisioned + Auto ScalingPredictable traffic patternsPay 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.


This is the simplest approach. DynamoDB automatically handles all capacity scaling.

AWS Console Method

  1. Open the DynamoDB console
  2. Select your table from the list
  3. Click the Additional settings tab
  4. In the Read/write capacity settings section, click Edit
  5. Under Capacity mode, select On-demand
  6. 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

  1. Open the DynamoDB console
  2. Select your table from the list
  3. Click the Additional settings tab
  4. In the Read/write capacity settings section, click Edit
  5. Under Capacity mode, select Provisioned
  6. 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%)
  7. For Write capacity, check Auto scaling
    • Set the same parameters as read capacity
  8. 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:

  1. Open the DynamoDB console
  2. Select your table
  3. Click the Additional settings tab
  4. 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

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.