← All posts

dynamodb · aws · pricing

DynamoDB Pricing: Why Writes Cost More Than You Think

By ·

DynamoDB pricing looks like the cheapest line on an AWS bill. In on-demand mode, a million writes costs $0.625 and a million reads costs $0.125 (DynamoDB on-demand pricing, US East, checked 2026-10-14 against the AWS Price List). So people estimate their traffic, multiply, and get a number in the single dollars. Then the bill says $180.

Almost always, the gap is one of three things: item size, indexes, or a table that should have left on-demand a year ago.

You pay per unit, not per request

AWS never bills you for “a write”. It bills write request units, and one unit covers up to 1 KB of item. A read request unit covers up to 4 KB for a strongly consistent read; an eventually consistent read, which is the default, costs half a unit. Transactional reads and writes cost double. The sizes round up per item, so a 1.1 KB item costs two write units (how DynamoDB counts read and write units).

A staircase chart of DynamoDB write units by item size: 0.9 KB costs 1 unit, 1.1 KB costs 2, 2.1 KB costs 3, and a 9.5 KB item costs 10 units per write

That staircase is the whole story for most tables. Writes are four times as sensitive to item size as reads, and they cost five times as much per unit to begin with.

Here’s a made-up but very ordinary example. An app writes 30 million times a month and reads 150 million times. Its items average 2 KB.

  • Writes: 30 million × 2 units = 60 million write units, $37.50.
  • Reads: 150 million × 1 unit × 0.5 (eventually consistent) = 75 million read units, $9.38.

The app reads five times more often than it writes and pays four times more for the writes. Now let the same items grow to 9.5 KB, because someone stored an activity log inside the user record. Writes become 300 million units, $187.50. Reads go to 3 units each, so 225 million units, $28.13. Same traffic, same code paths, bill up by $169.

Updating one field still pays for the whole item

This catches people who know the first part. An UpdateItem that changes a single attribute is billed on the size of the whole item, before or after the update, whichever is bigger. So the lastSeenAt timestamp you bump on every request pays for the entire profile it sits in, every time.

The fix is boring and works: move the fast-changing attributes into their own small item, keyed next to the big one. One extra read in a few places, and the hot write drops from 10 units to 1.

Indexes are writes too

Every global secondary index keeps its own copy of the attributes you project into it, and every write that changes one of those attributes also writes to the index. A table with three GSIs that project ALL can pay four times for a single update. Most tables we look at have at least one index nobody queries any more. If you’re not sure, check its read metrics in CloudWatch: an index with zero reads for a month is pure write cost. Projecting only the keys an index needs (KEYS_ONLY or INCLUDE) is the other half.

On-demand or provisioned

On-demand charges per request unit and scales instantly. Provisioned charges per capacity unit per hour, whether you use it or not: $0.00065 per write capacity unit-hour and $0.00013 per read capacity unit-hour in US East (provisioned capacity pricing), with 25 of each free.

For the example above with 2 KB items, steady traffic works out to about 23 write units and 29 read units per second on average. Give auto scaling a 70% target and you’d provision around 33 WCU and 41 RCU. After the free 25 of each, that’s roughly $5.30 a month for throughput, against $46.88 on-demand. That’s the case for provisioned in one line.

It only holds if the traffic really is steady. A table that sits idle all night and gets hammered at 9 am will either throttle on provisioned or need so much headroom that on-demand wins. Our rule: start on-demand, look at a month of CloudWatch consumed capacity, and switch the tables that look like a flat line. You can switch a table between modes, though AWS limits how often you can go back and forth (read/write capacity modes).

The quieter lines

Storage is $0.25 per GB-month after the first 25 GB, which is rarely the problem. Point-in-time recovery adds $0.20 per GB-month on top, and it’s worth having on any table you can’t rebuild. The Standard-IA table class drops storage to $0.10 per GB-month but makes every read and write about 25% more expensive ($0.78 and $0.155 per million), so it only pays on tables that are mostly storage and rarely touched, like old orders or audit logs.

Global tables bill every replicated write again in each extra region, and streams, exports and data transfer each get their own line. None of them are big unless you turned on something you forgot about.

You can plug your own numbers into our DynamoDB pricing calculator, which shows the same table on provisioned capacity next to the on-demand bill. AWS’s own Pricing Calculator covers the rarer lines if you need them.

Want us to look at your bill?

No upfront fee: for six months you pay half of what we save you each month, then you keep all of it. Nothing saved, nothing owed.