When to Choose DynamoDB On-Demand Capacity for Variable Workloads
Learn how DynamoDB On‑Demand capacity automatically scales to handle traffic spikes, see a worked flash‑sale example, and understand when it’s cheaper than provisioned mode.
22 Jan 2026, 01:00 UTC

Problem: unpredictable traffic forces over‑provisioning or throttling
Many applications experience traffic that changes minute‑by‑minute – a retail flash‑sale, a gaming event, or a nightly batch job. If you provision DynamoDB read/write capacity based on peak estimates you pay for idle resources; if you provision for average load you risk throttling during spikes.
Thesis: DynamoDB On‑Demand mode removes capacity planning by scaling per‑request, trading predictable operational effort for a usage‑based cost model
On‑Demand lets the service allocate read and write capacity automatically, charging you for each request and GB‑month of storage. This post walks through a concrete example, shows how to verify the behavior, and outlines the trade‑offs you should monitor.
Worked example: retail API flash‑sale
Imagine an API that writes order details to a DynamoDB table. Normal traffic is 5 K writes per second, but during a flash‑sale it jumps to 200 K writes per second for five minutes.
Step 1 – create the table in On‑Demand mode
# Run in a terminal with AWS CLI v2
# Required IAM permissions: dynamodb:CreateTable, dynamodb:DescribeTable
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions AttributeName=OrderId,AttributeType=S \
--key-schema AttributeName=OrderId,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--region us-east-1
The --billing-mode PAY_PER_REQUEST flag selects On‑Demand.
Step 2 – generate baseline load
Use a simple Lambda function (or an EC2 instance) that calls PutItem in a loop. Required permissions for the function: dynamodb:PutItem and logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents.
# Example Python snippet (run inside Lambda)
import boto3, time
client = boto3.client('dynamodb', region_name='us-east-1')
for i in range(5000): # 5 K writes/sec approx
client.put_item(
TableName='Orders',
Item={'OrderId': {'S': f'order-{i}'}, 'Qty': {'N': '1'}}
)
time.sleep(1)
Run this for a few minutes and watch CloudWatch metric ConsumedWriteCapacityUnits. It should hover around 5 K units (1 write capacity unit = 1 KB write per second for items ≤1 KB). No throttling errors (ProvisionedThroughputExceededException) appear.
Step 3 – simulate the flash‑sale spike
Increase the loop to 200 K iterations per second for five minutes. You can achieve this by launching multiple concurrent Lambda invocations or using a load‑testing tool such as hey or locust pointed at the Lambda endpoint.
During the spike, observe:
ConsumedWriteCapacityUnitsrises to ~200 K (or more, depending on item size).- No throttling errors are returned; the service scales within seconds.
- Latency (measured by
SuccessfulRequestLatency) stays within the typical range (often < 50 ms for 1 KB items).
After the spike ends, the metric drops back to baseline as the service scales down.
Verification steps you can run yourself
- Create an On‑Demand table as shown above.
- Deploy a load‑generator that emits a steady baseline (e.g., 5 K writes/sec) for 10 minutes.
- Record the average
ConsumedWriteCapacityUnitsand anyThrottledRequests. - Increase the load to 2‑3× baseline for 2‑3 minutes.
- Confirm that consumed capacity rises proportionally and throttling remains zero.
- Check the Billing dashboard for the period; compare the On‑Demand cost to the estimated cost of provisioning enough capacity to handle the peak (e.g., 200 K WCUs).
If you see throttling or latency spikes, verify that your load generator is not hitting API‑gateway or Lambda concurrency limits first.
Trade‑offs and limitations
On‑Demand eliminates capacity‑planning overhead but can become more expensive than provisioned mode when utilization stays high for extended periods. AWS guidance suggests the break‑even point is around 60‑70 % average utilization of the equivalent provisioned capacity. Monitor ConsumedReadCapacityUnits and ConsumedWriteCapacityUnits over time; if the average trends above that threshold, consider switching to provisioned mode with auto‑scaling.
Because scaling is reactive, a micro‑burst (e.g., a sudden jump from 0 to 200 K writes in < 1 second) may experience a brief latency increase while the service allocates partitions. Applications that cannot tolerate sub‑second latency spikes should buffer writes (e.g., via SQS) or provision a baseline capacity.
Actionable closing
For workloads with unpredictable or spiky traffic – such as event‑driven APIs, gaming leaderboards, or periodic batch jobs – start with DynamoDB On‑Demand. Use the verification steps above to confirm that scaling behaves as expected and to gather real‑world cost data. Set a CloudWatch alarm on average consumed capacity; if it consistently exceeds 60‑70 % of the projected provisioned need, evaluate a switch to provisioned mode with auto‑scaling to optimize cost while retaining performance.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.