Skip to content
AWS aws databases 5 min read

DynamoDB Capacity Modes

Every Amazon DynamoDB table needs a way to decide how much read and write throughput it can handle. DynamoDB gives you two ways to pay for that throughput, called capacity modes: on-demand and provisioned. Picking the right one is the single biggest lever you have over your DynamoDB bill, and the good news is you can switch between them on a live table. This page explains how each mode works, how to set it from the Console and the AWS CLI (Command Line Interface, the official AWS terminal tool), and a simple rule of thumb for choosing.

Capacity units, in plain English

Before comparing the modes, you need two terms.

  • A WCU (Write Capacity Unit) is one write per second of an item up to 1 KB. Writing a 1.5 KB item costs 2 WCUs.
  • An RCU (Read Capacity Unit) is one strongly consistent read per second of an item up to 4 KB. An eventually consistent read (slightly stale data, but cheaper) costs half an RCU.

Both modes use these same units under the hood. The difference is whether you reserve capacity ahead of time (provisioned) or just pay for what you use request by request (on-demand).

On-demand capacity

On-demand mode means you do not set any throughput numbers at all. DynamoDB instantly serves whatever traffic shows up, and you pay per request: per million write request units and per million read request units. There is nothing to tune and nothing to scale.

When to use this: new applications where you cannot predict traffic, workloads that are spiky or bursty (a flash sale, a viral post, a batch job that runs once a day), or any table where you would rather not babysit capacity. It is also the safest default while you are learning.

When NOT to use this: a high-volume table running at a steady, predictable rate around the clock. At large steady scale, on-demand can cost several times more than well-tuned provisioned capacity.

Set on-demand in the Console

  1. Open the DynamoDB console and go to Tables.
  2. Select your table, then open the Additional settings tab.
  3. Under Read/write capacity settings, choose Edit.
  4. Select On-demand and choose Save changes.

Set on-demand with the CLI

aws dynamodb update-table \
  --table-name Orders \
  --billing-mode PAY_PER_REQUEST

Output:

{
    "TableDescription": {
        "TableName": "Orders",
        "TableStatus": "UPDATING",
        "BillingModeSummary": {
            "BillingMode": "PAY_PER_REQUEST"
        }
    }
}

Provisioned capacity

In provisioned mode you tell DynamoDB how many RCUs and WCUs the table should keep ready. You pay for that reserved capacity by the hour whether you use it or not. If traffic exceeds what you reserved, requests can be throttled (rejected with a ProvisionedThroughputExceededException) unless burst capacity covers the spike.

When to use this: steady, predictable traffic where you know roughly how many reads and writes per second you need. At consistent high volume it is meaningfully cheaper than on-demand, and reserved capacity pricing can push the savings further.

When NOT to use this: unpredictable or rarely-used tables, because you either over-provision (paying for idle capacity) or under-provision (causing throttling).

Auto scaling

You almost never run provisioned mode with fixed numbers. Instead you enable auto scaling, which watches utilization and raises or lowers the provisioned RCUs/WCUs between a floor and ceiling you set, aiming for a target utilization (70% is the common default). This gives you provisioned pricing while still adapting to daily peaks and troughs.

Set provisioned with auto scaling in the Console

  1. Open the table, go to Additional settings, and choose Edit under capacity settings.
  2. Select Provisioned.
  3. Tick Auto scaling for reads and writes.
  4. Set the minimum and maximum capacity units and the target utilization (for example min 5, max 4000, target 70%).
  5. Choose Save changes.

Set provisioned with the CLI

First switch the table to provisioned mode with a baseline:

aws dynamodb update-table \
  --table-name Orders \
  --billing-mode PROVISIONED \
  --provisioned-throughput ReadCapacityUnits=10,WriteCapacityUnits=10

Then register the table with Application Auto Scaling and attach a target-tracking policy for writes:

aws application-autoscaling register-scalable-target \
  --service-namespace dynamodb \
  --resource-id "table/Orders" \
  --scalable-dimension "dynamodb:table:WriteCapacityUnits" \
  --min-capacity 10 \
  --max-capacity 4000

aws application-autoscaling put-scaling-policy \
  --service-namespace dynamodb \
  --resource-id "table/Orders" \
  --scalable-dimension "dynamodb:table:WriteCapacityUnits" \
  --policy-name OrdersWriteScaling \
  --policy-type TargetTrackingScaling \
  --target-tracking-scaling-policy-configuration \
    '{"TargetValue":70.0,"PredefinedMetricSpecification":{"PredefinedMetricType":"DynamoDBWriteCapacityUtilization"}}'

Output:

{
    "PolicyARN": "arn:aws:autoscaling:us-east-1:111122223333:scalingPolicy:...:resource/dynamodb/table/Orders:policyName/OrdersWriteScaling"
}

Repeat the last two commands with dynamodb:table:ReadCapacityUnits and DynamoDBReadCapacityUtilization to auto scale reads as well.

On-demand vs provisioned — when to use which

FactorOn-demand (PAY_PER_REQUEST)Provisioned + auto scaling
Pricing modelPer request (per million read/write units)Per reserved RCU/WCU per hour
ManagementZero — nothing to tuneSet min/max/target; mostly hands-off
Scaling speedInstantAdapts over minutes, not seconds
Best traffic shapeSpiky, bursty, unknown, low/idleSteady, predictable, high volume
Throttling riskEssentially nonePossible if a spike outruns scaling
Cost at high steady loadHigher (often several times more)Lower; cheapest with reserved capacity

Rule of thumb: Start every new table on on-demand. Once the table is busy and its traffic settles into a predictable daily pattern, switch to provisioned with auto scaling to cut the bill.

Cost gotcha: On-demand is a fantastic default, but it is not the cheapest at scale. A table doing tens of thousands of writes per second all day can cost several times more on on-demand than the same workload on well-tuned provisioned capacity. Don’t leave a high, steady-volume table on on-demand by accident — that surprise is one of the most common DynamoDB overspends.

You can switch modes on a live table, but only once every 24 hours, so plan deliberately rather than flipping back and forth.

Best Practices

  • Default new and unpredictable tables to on-demand; you avoid throttling and have nothing to manage.
  • Watch the ConsumedReadCapacityUnits and ConsumedWriteCapacityUnits CloudWatch metrics for a couple of weeks before deciding a table is “predictable.”
  • For steady high-volume tables, move to provisioned + auto scaling, then consider reserved capacity for the floor you always use to save further.
  • Set auto scaling target utilization around 70% — high enough to be cost-efficient, low enough to absorb normal spikes.
  • Give auto scaling a sensible maximum so a runaway client or attack cannot scale your bill without limit.
  • Remember Global Secondary Indexes have their own capacity; set their mode and auto scaling too, not just the base table.
  • Alarm on ThrottledRequests so you catch under-provisioning before users feel it.
Last updated June 15, 2026
Was this helpful?