DynamoDB On-Demand vs Provisioned
Key concepts
On-demand pricing
Provisioned capacity
Auto scaling
Reserved capacity
Workload pattern analysis
Overview
Amazon DynamoDB offers two capacity modes that determine how you are charged for read and write throughput: On-Demand and Provisioned. Selecting the right capacity mode is critical for cost optimization and is a frequent topic on the SAA-C03 exam. Understanding when to use each mode, how auto-scaling works, and how to leverage reserved capacity can significantly impact your AWS bill.
Core Concept
DynamoDB capacity modes represent a fundamental trade-off: On-Demand offers instant scalability with pay-per-request pricing (higher per-request cost but zero capacity planning), while Provisioned offers lower per-unit costs but requires capacity planning and may result in throttling if misconfigured. The exam tests your ability to select the appropriate mode based on workload patterns.
The exam frequently presents scenarios where you must choose between On-Demand and Provisioned capacity based on workload predictability, cost constraints, and traffic patterns. Remember: On-Demand is ideal for unpredictable or spiky workloads, while Provisioned with auto-scaling is better for predictable, steady traffic with cost optimization requirements.
Key Concepts
DynamoDB Capacity Units

Read Capacity Units (RCUs)
Definition: One RCU represents the throughput for one strongly consistent read per second, or two eventually consistent reads per second, for items up to 4 KB in size.
Key Calculations:
- Strongly Consistent Read: 1 RCU = 1 read/second for items up to 4 KB
- Eventually Consistent Read: 1 RCU = 2 reads/second for items up to 4 KB
- Transactional Read: 2 RCUs = 1 transactional read/second for items up to 4 KB
Size Calculation: Items larger than 4 KB require additional RCUs. Round up to the next 4 KB boundary.
Example: Reading a 6 KB item with strong consistency requires 2 RCUs (6 KB / 4 KB = 1.5, rounded up to 2)
Write Capacity Units (WCUs)
Definition: One WCU represents the throughput for one write per second for items up to 1 KB in size.
Key Calculations:
- Standard Write: 1 WCU = 1 write/second for items up to 1 KB
- Transactional Write: 2 WCUs = 1 transactional write/second for items up to 1 KB
Size Calculation: Items larger than 1 KB require additional WCUs. Round up to the next 1 KB boundary.
Example: Writing a 2.5 KB item requires 3 WCUs (2.5 KB / 1 KB = 2.5, rounded up to 3)
On-Demand Capacity Mode

On-Demand Pricing Model
Purpose: Pay-per-request pricing with instant, automatic scaling for unpredictable workloads
Key Characteristics:
- No capacity planning required - DynamoDB scales instantly
- Charged per request: Read Request Units (RRUs) and Write Request Units (WRUs)
- Can handle thousands of requests per second immediately
- Tables can instantly accommodate up to 2x the previous peak traffic
- No minimum fees or idle capacity charges
- Switch from Provisioned to On-Demand once every 24 hours
Pricing (US-East-1, approximate):
- Write Request Unit: $1.25 per million WRUs
- Read Request Unit: $0.25 per million RRUs
Best For: New applications with unknown traffic, applications with unpredictable traffic, spiky or seasonal workloads, development/test environments
On-Demand Scaling Behavior
Initial Throughput: New tables start with capacity for up to 4,000 WRUs or 12,000 RRUs per second
Automatic Scaling:
- DynamoDB automatically adapts to actual traffic patterns
- Can instantly accommodate up to double the previous peak
- If traffic exceeds 2x previous peak, DynamoDB continues to accommodate but may throttle briefly while scaling
Traffic Spikes:
- Previous peak: The highest traffic level the table has experienced
- If a spike exceeds 2x the previous peak, gradual increase is recommended
- Use adaptive capacity to automatically isolate hot partitions
No Throttling (within limits): On-Demand mode virtually eliminates throttling for most workloads as long as traffic doesn't spike to more than double the previous peak instantly
Provisioned Capacity Mode

Provisioned Capacity Overview
Purpose: Pre-allocate read and write capacity for predictable workloads at lower per-unit costs
Key Characteristics:
- Specify expected reads/writes per second
- Charged for provisioned capacity regardless of usage
- Lower per-unit cost than On-Demand (~70% less expensive at scale)
- Risk of throttling if actual traffic exceeds provisioned capacity
- Can use burst capacity (unused capacity accumulates for up to 5 minutes)
- Switch from On-Demand to Provisioned once every 24 hours
Pricing (US-East-1, approximate):
- Write Capacity Unit: $0.00065 per WCU per hour ($0.47/month per WCU)
- Read Capacity Unit: $0.00013 per RCU per hour ($0.09/month per RCU)
Best For: Predictable, consistent workloads; production applications with known traffic patterns; cost-sensitive applications with steady traffic
Burst Capacity
Purpose: Handle short-term traffic spikes without throttling
How It Works:
- DynamoDB reserves unused read/write capacity
- Accumulated over previous 5 minutes (300 seconds)
- Can consume up to 300 seconds of unused capacity instantaneously
- Provides a buffer for brief traffic spikes
Calculation Example:
- Provisioned: 100 WCUs
- If using 50 WCUs average, 50 unused WCUs accumulate
- After 5 minutes: 50 x 300 = 15,000 burst write capacity available
- Can handle spike of up to 15,000 writes instantly (plus ongoing 100 WCU)
Limitations:
- Not designed for sustained high traffic
- Once depleted, requests are throttled
- Not guaranteed - shared resource pool
Auto Scaling Configuration

DynamoDB Auto Scaling
Purpose: Automatically adjust provisioned capacity based on actual utilization
Key Components:
- Target Utilization: Percentage of provisioned capacity to maintain (20-90%, default 70%)
- Minimum Capacity: Floor for scaling down
- Maximum Capacity: Ceiling for scaling up
- Scale-out Cooldown: Wait time after scaling up before next scale-out (default 60 seconds)
- Scale-in Cooldown: Wait time after scaling down before next scale-in (default 60 seconds)
How It Works:
- CloudWatch monitors consumed capacity metrics
- Application Auto Scaling evaluates against target utilization
- When utilization exceeds/falls below target, scaling action triggers
- DynamoDB adjusts provisioned capacity within min/max bounds
Best For: Production workloads with variable but somewhat predictable patterns, applications with daily/weekly traffic cycles
Auto Scaling Policies
Target Tracking Scaling: Primary method for DynamoDB auto-scaling
Configuration Parameters:
- TargetValue: Target utilization percentage (e.g., 70%)
- ScaleInCooldown: Seconds to wait before scaling down
- ScaleOutCooldown: Seconds to wait before scaling up
- DisableScaleIn: Optional - prevent automatic scale-down
Important Considerations:
- Auto-scaling reacts to changes, not predicts them
- Lag time: 2-5 minutes to scale in response to traffic changes
- For sudden spikes, provisioned capacity + burst may not be sufficient
- Pre-scaling (scheduled scaling) recommended for known traffic events
- GSIs can have independent auto-scaling policies
CloudWatch Metrics Used:
ConsumedReadCapacityUnitsConsumedWriteCapacityUnitsProvisionedReadCapacityUnitsProvisionedWriteCapacityUnits
Reserved Capacity
Reserved Capacity Discounts
Purpose: Significant discounts for committed DynamoDB usage over 1 or 3 years
Key Characteristics:
- Up to 77% discount compared to on-demand pricing
- Requires upfront commitment (1-year or 3-year terms)
- Applies to Provisioned capacity mode only
- Reserved in specific AWS Region
- 100 RCU minimum, 100 WCU minimum per reservation
- Can purchase multiple reservations
Discount Levels (approximate): | Term | Payment Option | Discount vs Provisioned | |------|----------------|------------------------| | 1 Year | No Upfront | ~25% | | 1 Year | Partial Upfront | ~42% | | 1 Year | All Upfront | ~44% | | 3 Year | No Upfront | ~53% | | 3 Year | Partial Upfront | ~75% | | 3 Year | All Upfront | ~77% |
Best For: Production workloads with consistent, predictable baseline capacity; long-term applications with stable traffic patterns
Reserved Capacity Planning
Strategy: Reserve baseline capacity, use On-Demand or auto-scaling for peaks
Planning Steps:
- Analyze 30+ days of CloudWatch metrics for baseline consumption
- Identify minimum consistent utilization (your baseline)
- Reserve capacity for 70-80% of baseline (safety margin)
- Configure auto-scaling for traffic above reserved capacity
- Consider On-Demand for highly variable workloads
Important Notes:
- Reserved capacity is use-it-or-lose-it (no rollover)
- Cannot transfer between regions
- Applies automatically to matching tables
- Can combine with auto-scaling for cost optimization
Example Architecture:
- Reserved: 500 WCU, 1000 RCU (baseline)
- Auto-scaling: 500-2000 WCU, 1000-5000 RCU (variable)
- Peak handling through auto-scaling above reserved baseline
Workload Pattern Analysis
Capacity Mode Selection by Workload Pattern
| Workload Pattern | Recommended Mode | Key Reasoning | Cost Impact |
|---|---|---|---|
| New application, unknown traffic | On-Demand | No capacity planning needed, zero risk of over-provisioning | Higher per-request but no waste |
| Spiky, unpredictable traffic | On-Demand | Instant scaling, no throttling risk | Pay only for actual usage |
| Consistent, predictable traffic | Provisioned + Auto-Scaling | Lower per-unit cost, controlled scaling | Up to 70% cheaper than On-Demand |
| Scheduled peaks (e.g., daily batch) | Provisioned + Scheduled Scaling | Pre-scale before known peaks | Optimized cost with predictable scaling |
| Baseline + variable peaks | Reserved + Auto-Scaling | Reserved for baseline, auto-scale for peaks | Maximum savings with flexibility |
| Development/Test environment | On-Demand | Minimal usage, no idle costs | Zero cost when not in use |
| Seasonal business (e.g., retail) | On-Demand or aggressive auto-scaling | Handle 10-100x traffic spikes | Avoid paying for year-round peak capacity |
# Get table description including billing mode
aws dynamodb describe-table \
--table-name my-table \
--query 'Table.{BillingMode: BillingModeSummary.BillingMode, ProvisionedThroughput: ProvisionedThroughput}'
# List all tables with their billing modes
aws dynamodb list-tables --query 'TableNames' | \
xargs -I {} aws dynamodb describe-table \
--table-name {} \
--query '{TableName: Table.TableName, BillingMode: Table.BillingModeSummary.BillingMode}'# Switch to On-Demand mode
aws dynamodb update-table \
--table-name my-table \
--billing-mode PAY_PER_REQUEST
# Switch to Provisioned mode with specific capacity
aws dynamodb update-table \
--table-name my-table \
--billing-mode PROVISIONED \
--provisioned-throughput ReadCapacityUnits=100,WriteCapacityUnits=50# Register scalable target for write capacity
aws application-autoscaling register-scalable-target \
--service-namespace dynamodb \
--resource-id "table/my-table" \
--scalable-dimension "dynamodb:table:WriteCapacityUnits" \
--min-capacity 5 \
--max-capacity 1000
# Create target tracking scaling policy
aws application-autoscaling put-scaling-policy \
--service-namespace dynamodb \
--resource-id "table/my-table" \
--scalable-dimension "dynamodb:table:WriteCapacityUnits" \
--policy-name "WriteCapacityScaling" \
--policy-type "TargetTrackingScaling" \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "DynamoDBWriteCapacityUtilization"
},
"ScaleOutCooldown": 60,
"ScaleInCooldown": 60
}'
# Configure auto scaling for read capacity
aws application-autoscaling register-scalable-target \
--service-namespace dynamodb \
--resource-id "table/my-table" \
--scalable-dimension "dynamodb:table:ReadCapacityUnits" \
--min-capacity 10 \
--max-capacity 5000
aws application-autoscaling put-scaling-policy \
--service-namespace dynamodb \
--resource-id "table/my-table" \
--scalable-dimension "dynamodb:table:ReadCapacityUnits" \
--policy-name "ReadCapacityScaling" \
--policy-type "TargetTrackingScaling" \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "DynamoDBReadCapacityUtilization"
},
"ScaleOutCooldown": 60,
"ScaleInCooldown": 60
}'# Get consumed write capacity for last hour
aws cloudwatch get-metric-statistics \
--namespace AWS/DynamoDB \
--metric-name ConsumedWriteCapacityUnits \
--dimensions Name=TableName,Value=my-table \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 300 \
--statistics Average Sum Maximum
# Get throttled requests count
aws cloudwatch get-metric-statistics \
--namespace AWS/DynamoDB \
--metric-name ThrottledRequests \
--dimensions Name=TableName,Value=my-table \
--start-time $(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 3600 \
--statistics Sum
# Check current provisioned vs consumed capacity
aws cloudwatch get-metric-data \
--metric-data-queries '[
{"Id": "provisioned", "MetricStat": {"Metric": {"Namespace": "AWS/DynamoDB", "MetricName": "ProvisionedWriteCapacityUnits", "Dimensions": [{"Name": "TableName", "Value": "my-table"}]}, "Period": 300, "Stat": "Average"}},
{"Id": "consumed", "MetricStat": {"Metric": {"Namespace": "AWS/DynamoDB", "MetricName": "ConsumedWriteCapacityUnits", "Dimensions": [{"Name": "TableName", "Value": "my-table"}]}, "Period": 300, "Stat": "Average"}}
]' \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ)# List available reserved capacity offerings
aws dynamodb describe-reserved-capacity-offerings \
--query 'ReservedCapacityOfferings[*].{OfferingId: ReservedCapacityOfferingId, Duration: Duration, ProductDescription: ProductDescription}'
# Purchase reserved capacity (requires valid offering ID)
aws dynamodb purchase-reserved-capacity-offerings \
--reserved-capacity-offering-id <offering-id> \
--capacity-to-reserve ReadCapacityUnits=100,WriteCapacityUnits=100
# List current reserved capacity
aws dynamodb describe-reserved-capacity \
--query 'ReservedCapacity[*].{TableName: ReservedCapacityId, State: State, StartTime: StartTime, Duration: Duration}'Best Practices
- Start with On-Demand for New Applications: Use On-Demand initially to establish traffic patterns, then switch to Provisioned once patterns are clear
- Use Auto-Scaling with Appropriate Target: Set target utilization to 70% (default) for most workloads, lower for latency-sensitive applications
- Monitor Throttling Metrics: Set CloudWatch alarms for
ThrottledRequeststo detect capacity issues early - Reserve Baseline Capacity: For stable production workloads, reserve 70-80% of baseline and auto-scale the remainder
- Configure GSI Auto-Scaling Separately: Global Secondary Indexes have independent capacity - configure auto-scaling for each GSI
- Use Scheduled Scaling for Known Peaks: Pre-scale before anticipated traffic spikes (marketing campaigns, product launches)
- Review Capacity Monthly: Use AWS Cost Explorer to identify over-provisioned tables and optimize
- Consider Table Class: Use DynamoDB Standard-IA for infrequently accessed data to reduce storage costs
Common Exam Scenarios
Exam Scenario Decision Guide
| Scenario | Recommended Solution | Key Reasoning |
|---|---|---|
| Startup launching MVP with unknown user adoption | On-Demand capacity | No upfront capacity planning, scales with growth, zero cost when idle |
| E-commerce site with predictable daily traffic patterns | Provisioned with Auto-Scaling | Cost optimization for known patterns, auto-scale handles variations |
| Gaming application with massive, unpredictable player spikes | On-Demand capacity | Instant scaling without throttling risk, worth premium pricing |
| Financial services with steady transaction volume | Provisioned with Reserved Capacity | Maximum cost savings for consistent, predictable workloads |
| Application experiencing frequent throttling | Increase provisioned capacity or switch to On-Demand | Throttling indicates insufficient capacity for workload |
| Dev/test environment used 8 hours per day | On-Demand capacity | Pay only during active development, no idle costs |
| Batch processing job that runs nightly | Provisioned with Scheduled Scaling | Pre-scale before batch job, scale down after completion |
| Read-heavy analytics workload | Provisioned with aggressive read auto-scaling | Optimize for read-heavy pattern, scale reads independently |
Common Pitfalls
24-Hour Mode Switch Limitation
You can only switch between On-Demand and Provisioned capacity modes once every 24 hours per table. Plan capacity mode changes carefully and avoid frequent switching. If you need flexibility, consider staying on On-Demand or implementing robust auto-scaling.
Auto-Scaling Lag Time
Auto-scaling takes 2-5 minutes to react to traffic changes. It monitors CloudWatch metrics, evaluates policies, and then adjusts capacity. For sudden traffic spikes, this lag can cause throttling. Use burst capacity awareness, consider scheduled scaling for known peaks, or use On-Demand for truly unpredictable spikes.
GSI Capacity Independence
Global Secondary Indexes (GSIs) have completely independent capacity from the base table. Failing to configure auto-scaling for GSIs is a common mistake that leads to throttling on GSI queries even when the base table has sufficient capacity. Always configure auto-scaling for BOTH the table AND each GSI.
Reserved Capacity Use-It-or-Lose-It
Reserved capacity does not roll over. If you reserve 1000 WCUs but only use 500 WCUs, you still pay for 1000 WCUs. Over-reserving wastes money. Analyze at least 30 days of consumption data before purchasing reserved capacity, and reserve only 70-80% of your consistent baseline.
Ignoring Transactional Operations
DynamoDB transactions consume 2x the capacity of standard operations. A transactional write of a 1 KB item consumes 2 WCUs, not 1. When capacity planning, account for transactional operations separately to avoid unexpected throttling during transaction-heavy periods.
Related Services
Quick Reference
Capacity Mode Comparison
| Feature | On-Demand | Provisioned |
|---|---|---|
| Pricing Model | Pay-per-request | Pay-per-hour |
| Capacity Planning | None required | Required |
| Scaling | Instant, automatic | Auto-scaling with lag |
| Cost per Unit | Higher (~5x) | Lower |
| Throttling Risk | Very low | Possible if under-provisioned |
| Reserved Capacity | Not applicable | Available (up to 77% discount) |
| Best For | Unpredictable workloads | Predictable workloads |
| Switch Frequency | Once per 24 hours | Once per 24 hours |
Auto-Scaling Configuration Quick Reference
| Parameter | Description | Default | Recommended Range |
|---|---|---|---|
| Target Utilization | Percentage to maintain | 70% | 50-80% |
| Min Capacity | Floor for scaling | Varies | Baseline minimum |
| Max Capacity | Ceiling for scaling | Varies | 10x peak expected |
| Scale-Out Cooldown | Wait after scale up | 60s | 60-120s |
| Scale-In Cooldown | Wait after scale down | 60s | 300-900s |
Key CLI Commands
# Check current billing mode
aws dynamodb describe-table --table-name my-table \
--query 'Table.BillingModeSummary.BillingMode'
# Switch to On-Demand
aws dynamodb update-table --table-name my-table \
--billing-mode PAY_PER_REQUEST
# Switch to Provisioned
aws dynamodb update-table --table-name my-table \
--billing-mode PROVISIONED \
--provisioned-throughput ReadCapacityUnits=100,WriteCapacityUnits=50
# Check for throttling
aws cloudwatch get-metric-statistics \
--namespace AWS/DynamoDB \
--metric-name ThrottledRequests \
--dimensions Name=TableName,Value=my-table \
--period 3600 --statistics Sum \
--start-time $(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ)
Capacity Unit Calculations
| Operation | Item Size | Capacity Units |
|---|---|---|
| Strongly Consistent Read | Up to 4 KB | 1 RCU |
| Eventually Consistent Read | Up to 4 KB | 0.5 RCU |
| Transactional Read | Up to 4 KB | 2 RCUs |
| Standard Write | Up to 1 KB | 1 WCU |
| Transactional Write | Up to 1 KB | 2 WCUs |
Pricing Quick Reference (US-East-1, approximate)
On-Demand:
- Write Request Unit: $1.25 per million WRUs
- Read Request Unit: $0.25 per million RRUs
Provisioned:
- Write Capacity Unit: $0.00065/hour ($0.47/month)
- Read Capacity Unit: $0.00013/hour ($0.09/month)
Reserved Capacity (3-Year, All Upfront):
- Up to 77% discount on provisioned pricing
Test Your Knowledge
A startup is launching a new mobile application. User adoption is completely unknown, and they expect traffic patterns to be highly variable if the app goes viral. The development team has no experience with DynamoDB capacity planning. Which capacity mode should they choose?
A company runs an e-commerce platform with predictable daily traffic: 1,000 WCUs during business hours and 100 WCUs at night. They consistently use 800 WCUs average during peak hours. They want to minimize costs while ensuring no throttling. What is the MOST cost-effective configuration?
An application using DynamoDB Provisioned capacity is experiencing intermittent throttling during morning traffic spikes that occur between 8:00-8:15 AM daily. Auto-scaling is configured with 70% target utilization. What is the BEST solution to prevent throttling?
A DynamoDB table has the following CloudWatch metrics over 30 days: consistent 200 RCU consumption, occasional spikes to 500 RCU lasting 2-3 hours, and very rare spikes to 2000 RCU during monthly sales events. What capacity configuration provides the BEST balance of cost and performance?