Over-provisioned DynamoDB: paying for capacity you never use
Short version: With provisioned DynamoDB capacity you pay for the read/write units you reserve, used or not. Tables are routinely over-provisioned "to be safe" and then run at 5-10% utilization for years. Here is how to find them and pick the right fix: right-size, turn on auto-scaling, or move to on-demand.
Why over-provisioning happens
Someone sets a table to 1,000 RCU / 1,000 WCU during a launch or load test, traffic never materializes, and the provisioned numbers are never revisited. You keep paying for 1,000 units while consuming 50. Because DynamoDB does not bill a big scary line item, it hides.
Step 1 - Compare provisioned vs consumed
Check a table's provisioned capacity:
aws dynamodb describe-table --table-name my-table \
--query 'Table.ProvisionedThroughput.{Read:ReadCapacityUnits,Write:WriteCapacityUnits}'
Then pull actual consumption over the last week from CloudWatch:
aws cloudwatch get-metric-statistics \
--namespace AWS/DynamoDB --metric-name ConsumedReadCapacityUnits \
--dimensions Name=TableName,Value=my-table \
--start-time "$(date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ)" \
--end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--period 86400 --statistics Average Maximum \
--query 'Datapoints[].{Avg:Average,Max:Maximum}'
Average consumption far below provisioned (say, under 20%) means you are overpaying.
Step 2 - Pick the right fix
- Steady, predictable traffic that is just set too high -> lower the provisioned
numbers to match reality:
aws dynamodb update-table --table-name my-table \
--provisioned-throughput ReadCapacityUnits=100,WriteCapacityUnits=100 - Variable-but-known daily pattern -> enable auto-scaling so capacity tracks demand instead of sitting at a fixed ceiling.
- Spiky or unpredictable, low-average traffic -> switch to on-demand, which
bills per request with no reserved capacity:
aws dynamodb update-table --table-name my-table --billing-mode PAY_PER_REQUEST
The caveat: on-demand is not always cheaper
On-demand costs roughly 5-7x more per request than provisioned. It wins for spiky, low-average, or unpredictable workloads (you pay nothing when idle), but for steady high throughput provisioned + auto-scaling is far cheaper. Right-size based on the consumption pattern, not a blanket switch. You can change billing mode once per 24 hours, so decide deliberately.
Do it automatically
Cloud Cost Analyzer's dynamodb-over-provisioned rule flags tables running below 20%
utilization and estimates the right-sizing savings - alongside 89 other cost rules:
curl -sSL https://releases.dragonfractal.com/install.sh | sh
cca scan --provider aws
The agent runs in your environment with read-only access, so your AWS credentials never leave it. See the AWS setup and required IAM permissions
CLI Reference
aws dynamodb describe-tableaws dynamodb update-tableaws dynamodb describe-auto-scaling-settings