6. Capacity and cost
DynamoDB · 6. Capacity and costIn most databases, cost is a machine you rent and performance is a mystery you investigate. Here it is inverted: performance is guaranteed and cost is arithmetic you can do on paper. That is a genuine engineering advantage, and only if you actually do the arithmetic.
The units
Section titled “The units” 1 WCU = one write of up to 1 KB per second 1 RCU = one strongly consistent read of up to 4 KB per second = TWO eventually consistent reads of 4 KB
ROUNDING IS ALWAYS UP, PER ITEM a 1.2 KB write = 2 WCU a 0.1 KB write = 1 WCU a 9 KB strongly consistent read = 3 RCU a 9 KB eventually consistent read = 1.5 RCU TRANSACTIONS COST DOUBLE (ch 9) TransactWriteItems 2 WCU per KB per item TransactGetItems 2 RCU per 4 KB per itemTwo consequences fall straight out of the rounding rule: small items are proportionally expensive (a 100-byte write costs the same as a 1 KB one), and large items are linearly expensive (a 390 KB item costs 390 WCU to write). Chapter 13 uses both facts.
On-demand versus provisioned
Section titled “On-demand versus provisioned” ON-DEMAND (pay per request) ✓ no capacity planning at all ✓ scales instantly to any traffic shape ✓ perfect for new, spiky or unknown workloads ✗ roughly 5–7× the unit price of provisioned ✗ surprise traffic = surprise bill
PROVISIONED (pay per hour of capacity) ✓ much cheaper per request at steady load ✓ reserved capacity discounts it further ✓ auto-scaling adjusts within bounds ✗ throttling when traffic exceeds what you set ✗ auto-scaling reacts in MINUTES, not seconds THE DECISION, IN PRACTICE
new product, unknown traffic → ON-DEMAND steady 24/7 load → PROVISIONED + auto-scaling + reserved capacity predictable daily peaks → PROVISIONED with scheduled scaling sharp unpredictable spikes → ON-DEMAND development and test → ON-DEMANDYou can switch modes, with a cooldown between changes, so starting on-demand and moving to provisioned once the shape of the traffic is known is a perfectly good plan — and the order that wastes the least money.
Throttling and bursts
Section titled “Throttling and bursts” PROVISIONED TABLE, 100 WCU
traffic 80 WCU → fine traffic 120 WCU → burst capacity absorbs it for a while (unused capacity from the last ~5 minutes) sustained 120 → burst exhausted → ProvisionedThroughputExceededException → the SDK retries with backoff → your p99 latency climbs, then requests start failing THREE THINGS THAT LOOK LIKE THROTTLING TABLE capacity exceeded → raise capacity PARTITION ceiling hit → fix the key (ch 3) GSI capacity exceeded → raise the GSI, and it backpressures the table (ch 7)Distinguishing them is the whole diagnostic skill, because only the first is solved by money.
Doing the arithmetic
Section titled “Doing the arithmetic”A worked example, because this is the chapter’s real point.
APPLICATION 1,000,000 users each reads their profile 10×/day (1 KB) each writes an event 5×/day (0.5 KB) profile reads are eventually consistent
READS 10,000,000/day ÷ 86,400 ≈ 116/s 1 KB → 1 RCU strongly, 0.5 eventually ≈ 58 RCU sustained
WRITES 5,000,000/day ÷ 86,400 ≈ 58/s 0.5 KB → 1 WCU (rounded up!) ≈ 58 WCU sustained
PEAK traffic is not flat. assume 3× daily peak → provision ~175 RCU / ~175 WCU, or auto-scale between 60 and 250 ORDER-OF-MAGNITUDE COSTS (us-east-1 list prices, check current pricing — these move)
provisioned ~$0.00013 per WCU-hour ~$0.000025 per RCU-hour on-demand ~$1.25 per million writes ~$0.25 per million reads storage ~$0.25 per GB-month PITR backup ~$0.20 per GB-month streams ~$0.02 per 100k read requestsThe point is not the numbers — they change — but that you can compute them before writing code, from the access-pattern list of chapter 8. No other database in this collection lets you do that.
Where the bill actually goes wrong
Section titled “Where the bill actually goes wrong” ① SCANS ON A REQUEST PATH one endpoint doing a full scan per call. the table is small in dev and enormous in prod.
② INDEXES YOU FORGOT every GSI duplicates writes. four GSIs = 5× the write cost of the base table. (ch 7)
③ STRONGLY CONSISTENT BY DEFAULT some SDK wrappers default to strong reads. instant 2× on every read.
④ SMALL ITEMS, HUGE COUNTS a 60-byte telemetry item still costs 1 WCU. batching them into larger items cuts cost proportionally. (ch 13)
⑤ ON-DEMAND ON A STEADY WORKLOAD the convenience premium, paid forever.
⑥ TRANSACTIONS USED ROUTINELY double cost for guarantees a conditional write often provides. (ch 9)Watching it
Section titled “Watching it”aws cloudwatch get-metric-statistics --namespace AWS/DynamoDB \ --metric-name ConsumedWriteCapacityUnits \ --dimensions Name=TableName,Value=AppData \ --start-time 2026-09-22T00:00:00Z --end-time 2026-09-23T00:00:00Z \ --period 300 --statistics Sum ALERT ON ThrottledRequests > 0 (sustained) ReadThrottleEvents / WriteThrottleEvents ConsumedCapacity ÷ Provisioned > 80% SuccessfulRequestLatency p99 per-GSI consumed capacity — separately!Per-index metrics matter because a table can look healthy while one of its indexes is the thing failing.
The cost of an index, computed
Section titled “The cost of an index, computed”Chapter 7 says a GSI is a second copy. Here is what that means in money.
BASE TABLE 100 writes/s × 1 KB = 100 WCU
ADD ONE GSI, projection ALL every write also writes the index 100 writes/s × 1 KB = 100 WCU (index) ─────────────────────────────────────── total 200 WCU ← doubled
ADD THREE MORE GSIs total 500 WCU ← 5× PROJECTION CHANGES THE ARITHMETIC ALL index item ≈ base item → 1 WCU INCLUDE (2 small attrs) index item ≈ 0.3 KB → 1 WCU KEYS_ONLY index item ≈ 0.1 KB → 1 WCU
…all three still round UP to 1 WCU. Projections save meaningfully only when items are LARGE enough that the index copy crosses fewer KB boundaries.That is a genuinely counter-intuitive result and worth keeping: for small items, KEYS_ONLY saves storage and read cost but not write capacity, because everything rounds to one unit anyway.
Only writes that touch the index count
Section titled “Only writes that touch the index count” A write that does not change any index key or any projected attribute does NOT cost index capacity.
→ putting volatile attributes OUTSIDE the projection keeps hot updates off the index entirelyReserved capacity, briefly
Section titled “Reserved capacity, briefly” RESERVED CAPACITY • buy WCU/RCU for 1 or 3 years, up front or partially • roughly 50–75% off list, depending on term • applies to PROVISIONED capacity only — never to on-demand • per region, per account
WORTH IT WHEN the baseline is genuinely steady and you will still be running this table in a yearThe usual shape is reserved capacity for the floor, auto-scaling above it — you pay the discounted rate for the traffic you always have, and list price only for the peaks.
Cost controls worth having from day one
Section titled “Cost controls worth having from day one” □ ReturnConsumedCapacity in dev and in load tests □ a CloudWatch alarm on throttles □ AWS Budgets alert on the DynamoDB line item □ TTL on anything with a natural lifetime (ch 12) — TTL deletes are FREE, DeleteItem is not □ on-demand for non-production tables □ a decision, written down, about which reads may be eventually consistentThat TTL line is quietly one of the largest savings available: expiring old items with a TTL attribute costs nothing, while deleting them yourself costs a WCU each.
What to take from this chapter
Section titled “What to take from this chapter”- 1 WCU = 1 KB written per second; 1 RCU = 4 KB read strongly, or 8 KB eventually. Everything rounds up per item.
- Therefore small items are proportionally expensive and large items linearly so — both are levers.
- Transactions cost double.
- On-demand removes planning at roughly 5–7× the unit price; provisioned plus auto-scaling plus reserved capacity is far cheaper at steady load. Start on-demand, switch once the shape is known.
- Auto-scaling reacts in minutes, so sudden spikes throttle anyway; schedule capacity for known events.
- Throttling has three distinct causes — table capacity, the per-partition ceiling, and GSI capacity — and only the first is fixed by money.
- You can compute the bill from the access patterns before writing code. Do it.
- The six ways bills go wrong: scans on request paths, forgotten indexes, default strong reads, tiny items at huge counts, on-demand on steady load, and routine transactions.
- Turn on per-table and per-index metrics, alarm on throttles and 80% utilisation, and use TTL — which deletes for free.
Next: secondary indexes — local and global, what they cost, and the backpressure that makes a throttled index a table-wide problem.