Intermediate5 min read

DynamoDB On-Demand Throughput: Measured

How much throughput does a new DynamoDB on-demand table get?

A brand-new table serves about 4,130 writes per second — AWS documents 4,000 — and at least 12,700 eventually-consistent reads per second. We measured both on 2026-08-27 against a table created minutes earlier: writes pinned at 4,130 ±2/s across every over-baseline load we offered, and reads never throttled at all before our own load generator ran out of headroom.

Those two numbers, and everything else on this page, come from counting real requests against the live service — not from restating the documentation. The method, the raw data, and the three failed attempts are written up in the benchmark story; this page is the reference the numbers live on.

The write ceiling on a fresh table

Offered load ramped in 30-second windows against a table that had never seen traffic. Every request carried a ~1 KB item with a uniformly random key — no involved:

Offered (writes/s)AchievedThrottled requests
1,0001,0000
2,0002,0000
3,0003,0000
4,0004,0000
5,0004,13225,992
6,0004,13155,966
8,0004,134115,922

The documented 4,000 write/s baseline holds, with about 3% of headroom above it. The ceiling is remarkably flat: 4,132, 4,131, 4,134 achieved per second at 5,000, 6,000 and 8,000 offered. Latency does not degrade as you cross it — p50 write latency stayed at 4–5 ms in-region in every window. The service does not slow down; it rejects.

What the throttle actually returns

The first rejection arrived 0.9–3.8 seconds into each over-baseline window (the higher the offered rate, the sooner it came). Verbatim:

ThrottlingException: Throughput exceeds the current capacity of your table or index. DynamoDB is automatically scaling your table or index so please try again shortly. If exceptions persist, check if you have a hot key: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-partition-key-design.html

Two things to plan around. It is an HTTP 400, not a 5xx — a retry policy or alarm that only watches 5xx will miss on-demand throttling entirely (the SDKs do retry it by default; see ). And the hot-key hint is a default suggestion, not a diagnosis — our keys were uniformly random, so at small scale the first suspect for this message is the table-level ceiling, not your key schema. The four distinct throttling causes have their own guide.

The read ceiling

Reads ran against a second fresh table seeded with 1,000 items, as GetItems (~1 KB, 0.5 read units each):

Offered (reads/s)AchievedThrottled requests
4,0004,0000
8,0007,9410
12,00011,1190
16,00012,7620

Zero throttles at every rate. The documented 12,000 read/s baseline holds, and we could not find its actual edge: at 16,000/s offered, five of our eight runners saturated client-side, so 12,762/s is where our fleet topped out — not where DynamoDB did. Reads answered at 2–4 ms p50 in-region.

How the ceiling grows under sustained load

AWS documents that on-demand capacity grows to accommodate up to double the previous peak, and that exceeding double the previous peak within 30 minutes may throttle. We held 8,000 writes/s of offered load against one table for 34 contiguous minutes (four 8-minute waves with under a minute of pause between them) and watched the ceiling move, minute by minute:

WaveStartedAchieved writes/s, minute by minute
106:06 UTC4,019 → 4,001 → 4,001 → 3,999 → 3,998 → 4,000 → 4,000 → 4,000
206:15 UTC5,046 → 5,000 → 4,996 → 4,990 → 4,991 → 4,998 → 4,992 → 4,993
306:24 UTC5,046 → 4,973 → 4,991 → 4,981 → 4,983 → 4,989 → 4,993 → 5,978
406:32 UTC7,006 → 6,991 → 6,979 → 6,996 → 6,991 → 6,988 → 7,002 → 6,990

Reading the timeline:

  • The first ceiling is sticky. Through the entire first 8 minutes the table held at its ~4,000/s baseline — sustained over-demand did not move it within that window.
  • Growth arrives in ~1,000/s steps, not a ramp. The ceiling stepped to ~5,000/s around minute 9, ~6,000/s around minute 26, and ~7,000/s a minute later, then held 7,000/s flat to the end. Each step lands abruptly between one minute and the next. Two of the three steps landed near our wave boundaries, so the sub-minute pauses may interact with the growth mechanism — we report the timing as observed.
  • Half an hour of sustained demand did not double the ceiling. After 34 minutes at 8,000/s offered, the table served 7,000/s — 1.75× its starting ceiling, still short of both the offered rate and a clean doubling. Throttled requests fell wave over wave (1.9M → 0.5M) as capacity grew.
The live benchmark, replayed
Offered write rateMeasured points only — the selector snaps to the seven offers we ran.
ServedThrottled
Achieved rate4,000/s
Throttled requests0
Throttle share0%

At 4,000 offered writes/s the fresh table served every request — 4,000/s achieved, zero throttles in the 30-second window.

0 min
Ceiling this minute4,019/s
Throttle share49.6%
Plateau4,000/s

Minute 0: still on the 4,000/s rung — 4,019 writes/s served against a constant 8,000/s offered. The first ceiling is sticky: sustained overload alone has not moved it.

Offered (writes/s)AchievedThrottled requestsThrottle share
1,0001,000
2,0002,000
3,0003,000
4,0004,000
5,0004,13225,99217.3%
6,0004,13155,96631.1%
8,0004,134115,92248.3%
Plateau (writes/s)MinutesLength
4,0000–78 min
5,0008–2316 min
6,000241 min
7,00025–339 min

Measured live 2026-08-27/28 — method and raw data in the benchmark write-up.

If your launch-day traffic will exceed ~4,000 writes/s on a new table, pre-warm it: either drive synthetic load ahead of the event, or set the table's maximum on-demand throughput explicitly and let AWS provision for it. The on-demand vs provisioned guide covers when each mode wins, and auto scaling is the provisioned-mode counterpart of what you watched happen automatically here.

Two numbers that surprised us

  • Create-to-ACTIVE time varies 3×. A fresh on-demand table reached ACTIVE in 7.4 seconds on one run and 22 seconds on two others, same region, same schema. Budget for the slow case in any table-per-tenant or table-per-test design.
  • The whole benchmark cost $0.97. 672,116 billed writes and 1.08 million reads. The 34-minute sustained-growth run cost $12.67 more. Measuring the service yourself is cheaper than one wrong capacity decision — and you can price a workload like this ahead of time with the DynamoDB pricing calculator.

Scope and method, honestly

Everything above is one table per phase, one day, one region (us-east-1), ~1 KB items, uniform random keys. Per-partition limits (3,000 read units / 1,000 write units per second) sit below the table-level behavior measured here and have their own failure modes. Account-level quotas and the hard service limits are on the DynamoDB limits reference, measured the same way. And if you work against DynamoDB daily, DynoTable is our desktop client for it — built by the same team, with the same habit of checking claims against the live service before repeating them.

Updated