AWS DynamoDB Cost Optimization · Startup Guide
How to Reduce AWS DynamoDB Costs by 50–75%
DynamoDB pricing is complex - on-demand vs. provisioned, Reserved Capacity, GSI write multiplication, and the November 2024 50% price cut most teams haven’t accounted for. Most startups overpay by 50% or more.
DynamoDB Pricing Modes Compared
| Mode | Read cost | Write cost | Best for |
|---|---|---|---|
| On-demand (old pricing) | $0.25/million RRU | $1.25/million WRU | Highly unpredictable |
| On-demand (Nov 2024) | $0.125/million RRU | $0.625/million WRU | Unpredictable/bursty traffic |
| Provisioned (on-demand rates) | $0.00013/RCU-hr | $0.00065/WCU-hr | Predictable traffic |
| Reserved Capacity (1-yr) | ~53% off provisioned | ~53% off provisioned | Stable baseline workloads |
5 DynamoDB Cost Optimizations
Apply these in order - highest ROI first.
Switch on-demand tables to provisioned capacity mode
DynamoDB on-demand pricing charges per request: $1.25 per million read request units, $1.25 per million write request units (us-east-1). Provisioned capacity costs $0.00065 per RCU/hour and $0.00065 per WCU/hour - roughly 60–75% cheaper for predictable traffic patterns. The break-even point is any table receiving consistent traffic.
How to implement
- Check access patterns in CloudWatch: if traffic is consistent (not bursty), provisioned is cheaper
- Use the DynamoDB cost calculator: estimate your P95 read/write throughput
- Start with 10–20% headroom above your P95 throughput
- Enable DynamoDB Auto Scaling to adjust capacity within a min/max range automatically
- Set target utilization to 70% - this provides burst headroom without over-provisioning
Note: On-demand is the right choice for truly unpredictable or spiky traffic (e.g., a table that receives 10× normal traffic during a launch). For steady-state tables, provisioned with auto scaling is almost always cheaper.
Apply the November 2024 on-demand pricing reduction
In November 2024, AWS reduced DynamoDB on-demand pricing by 50% globally. Read Request Units dropped from $0.25 to $0.125 per million (us-east-1), Write Request Units from $1.25 to $0.625 per million. If you haven’t reviewed your bill since then, check that the new pricing is reflected - it applies automatically but is worth verifying.
How to implement
- Open AWS Cost Explorer → Service: DynamoDB → Usage Type: ReadRequestUnits, WriteRequestUnits
- Verify the per-unit cost reflects the Nov 2024 rates (ReadRU: $0.000000125, WriteRU: $0.000000625)
- If pricing looks wrong, open an AWS Support ticket - pricing changes apply automatically but billing anomalies do occur
- Re-evaluate the on-demand vs. provisioned decision with new pricing - the break-even point shifted
Note: The 50% price cut in November 2024 means that some tables which were previously better on provisioned may now be competitive on on-demand. Re-run the math with current pricing.
Purchase Reserved Capacity for baseline provisioned throughput
DynamoDB Reserved Capacity provides a 53–75% discount on provisioned read and write capacity for a 1-year or 3-year commitment. If you have tables with stable baseline throughput, Reserved Capacity is the highest-ROI DynamoDB optimization available.
How to implement
- DynamoDB console → Reserved Capacity → Purchase reserved capacity
- Buy reserved capacity equal to your minimum provisioned throughput (not the auto-scaled maximum)
- Reserved capacity applies globally to all tables in the region - no per-table assignment needed
- Start with 1-year no-upfront to validate before committing to 3-year terms
- Review monthly in Cost Explorer to ensure coverage is tracking
Note: Reserved Capacity is separate from EC2 Reserved Instances or Savings Plans. It specifically covers DynamoDB provisioned capacity and is purchased directly in the DynamoDB console.
Optimize Global Secondary Indexes
Each Global Secondary Index (GSI) on a DynamoDB table doubles the write cost - every write to the base table also writes to each GSI. Tables with 5–10 GSIs pay 5–10× the write cost of a single-table design. Unused or low-cardinality GSIs are pure waste.
How to implement
- List GSIs per table: aws dynamodb describe-table --table-name MyTable | jq .Table.GlobalSecondaryIndexes
- Check GSI usage in CloudWatch: look for IndexName → ConsumedReadCapacityUnits/ConsumedWriteCapacityUnits
- Delete GSIs with zero read consumption but high write consumption (write cost with no read value)
- Consolidate similar query patterns into fewer GSIs using composite sort keys
- For new tables: design single-table patterns that minimize GSI count
Note: This is a schema design concern, but has direct cost impact. A table with 8 GSIs pays for 9 write units per write (1 base + 8 GSIs). Removing 4 unused GSIs cuts write costs in half.
Enable DynamoDB Streams only where needed
DynamoDB Streams charges $0.02 per 100,000 read request units. If Streams are enabled on high-write tables but the stream is not actively consumed (e.g., a Lambda trigger was removed but the stream stays enabled), you’re paying for stream records that are never read.
How to implement
- List tables with streams enabled: aws dynamodb list-tables | xargs -I{} aws dynamodb describe-table --table-name {} | jq '.Table | select(.StreamSpecification.StreamEnabled==true)'
- Check Lambda event source mappings: are any Lambdas actually consuming the stream?
- Disable streams on tables where no consumer is attached
- For Kinesis Data Streams integration (DynamoDB Kinesis Stream Export): check if the Kinesis stream is being consumed
Note: Disabled DynamoDB Streams generate no charges. If you enabled streams for change data capture during a migration that completed months ago, they’re still charging you.
Frequently Asked Questions
When should I use DynamoDB on-demand vs. provisioned?
On-demand is better for new tables (unknown traffic), event-driven workloads with extreme spikes, and low-traffic tables where provisioned minimum (1 RCU/WCU) would over-provision. Provisioned with auto scaling is cheaper for any table with consistent traffic above ~5M requests/month.
What happened to DynamoDB pricing in November 2024?
AWS reduced DynamoDB on-demand read request prices by 50% (from $0.25 to $0.125 per million in us-east-1) and write request prices by 50% (from $1.25 to $0.625 per million). Global tables pricing also decreased. The change applied automatically to all accounts.
Does DynamoDB Reserved Capacity apply to all tables?
Yes. Reserved Capacity is a regional purchase that applies to all provisioned capacity in the region - you don’t need to assign it to specific tables. You buy a number of read and write capacity units, and any provisioned throughput in the region consumes from the reserved pool first.
Why does DynamoDB cost so much for high-write workloads?
Write capacity units are 5× more expensive than read capacity units in provisioned mode. Every GSI multiplies write costs. DynamoDB is cost-efficient for read-heavy workloads but expensive for write-heavy ones - consider Kinesis or SQS for high-throughput write pipelines that don’t need DynamoDB’s query model.
How do I see my DynamoDB costs by table?
Enable DynamoDB cost allocation tags: add a tag to each table (e.g., team=platform, service=checkout) and activate the tag as a cost allocation tag in Billing settings. Then Cost Explorer can group by tag to show cost per table. DynamoDB doesn’t break down costs by table natively.