Intermediate5 min read

DynamoDB On-Demand Throughput: Measured

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

A brand-new table sustains 4,000 writes per second, the number AWS documents. It was measured on 2026-08-27 against a table created minutes earlier.

Reads reached 12,762 eventually-consistent reads per second with no throttle, and the load generator ran out first.

Those two numbers, and everything else on this page, come from counting requests against the live service.

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

Load ramped in 30-second windows against a table that had never seen traffic. In both tables below, Target is the rate each window was scheduled at.

Every request carried a ~1 KB item with a uniformly random key, so no was involved:

Target (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

On writes the fleet sent the full target rate in every window, and the documented 4,000 write/s baseline holds. Achieved rates of 4,131 to 4,134 are 30-second averages.

A September retest with 10-second buckets showed each throttled step at 4,400–4,480/s for its first 10 seconds, then near 4,000/s.

Ten seconds at 4,400–4,480 and twenty at 4,000 average to 4,133–4,160 over 30 seconds, which brackets the measured 4,131–4,134.

Latency was timed on accepted writes only. Their p50 stayed at 4–5 ms in-region, except on one runner that hit its in-flight cap in the 8,000 window (p50 78 ms, p99 1,327 ms).

What the throttle returns

The first rejection arrived 3.8, 1.9 and 0.9 seconds into the 5,000, 6,000 and 8,000 windows. 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

It is an HTTP 400, not a 5xx. A retry policy or alarm that only watches 5xx misses on-demand throttling entirely. The SDKs retry it by default; see .

Alarm on the table's CloudWatch ThrottledRequests metric, or on WriteThrottleEvents and ReadThrottleEvents, instead. The throttling guide covers which metric names which cause.

The keys were uniformly random, so no single key was hot. On a ThrottlingException, AWS attaches a throttlingReasons field that names the limit that fired; this run did not record it.

The read ceiling

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

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

Zero throttles at every rate: DynamoDB accepted every read the fleet sent.

Above 4,000/s the fleet sent less than the target rate, because runners hit their in-flight cap (one, two, then five of eight). At the 16,000 schedule it sent, and DynamoDB accepted, 12,762 reads/s.

12,762 eventually-consistent reads/s is about 6,400 read units/s, roughly half of the 12,000 read units per second AWS gives a new on-demand table (the warm throughput docs state it in read units; the on-demand page says "12,000 reads per second").

The read ceiling was never reached. Runners below their cap saw 2–10 ms p50 reads in-region.

How the ceiling grows under sustained load

AWS says on-demand "instantly accommodates up to double the previous peak traffic on a table", and that "throttling can occur if you exceed double your previous peak within 30 minutes."

One fresh table was offered 8,000 writes/s in four 8-minute waves, with 32–39 second pauses between them:

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 wave held at 4,000/s. For all 8 minutes of wave 1, the table served its starting 4,000/s.
  • Three steps followed. Minutes count from the start of wave 1. The table reached ~5,000/s at 8.6 minutes (start of wave 2), ~6,000/s at 24.2 (late in wave 3) and ~7,000/s at 25.8 (start of wave 4).
  • Two of the three steps landed at a wave start, right after an idle pause. This one run cannot separate time under load from the pauses.
  • It never served 8,000/s. The run ended at 33.8 minutes with the table at 7,000/s. Throttled requests fell wave over wave, from 1.9M to 0.5M.
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 launch-day traffic will exceed 4,000 writes/s on a new table, raise its warm throughput (the rate a table can serve instantly) first.

Pass --warm-throughput WriteUnitsPerSecond=N to update-table, or to create-table for a new table. AWS bills it once, per unit of increase.

The raise is asynchronous: wait until the table's WarmThroughput.Status is ACTIVE. After it is increased, warm throughput can't be decreased.

Each GSI has its own warm throughput: --global-secondary-index-updates with an Update action on update-table, or a WarmThroughput member on each index in --global-secondary-indexes on create-table.

A GSI that throttles also throttles writes to the base table.

Maximum on-demand throughput is a different setting. AWS applies it on a best-effort basis, and burst capacity can briefly exceed it. It does not pre-warm a table.

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 more numbers

  • A fresh table was ACTIVE within about 22 seconds. The waiter polled every 20 seconds, so the true time may be shorter.
  • The ceiling run cost about $0.49 at list price. That covers 672,116 accepted writes and 1,078,047 reads in us-east-1. The sustained run cost about $6.33. Lambda, failed runs and probes are extra. You can price a workload like this with the DynamoDB pricing calculator.

Scope and method

Everything above is one table per phase, measured once on 2026-08-27 or 28 in us-east-1, plus one September retest for the 10-second burst, with ~1 KB items and uniform random keys. Retries were off; the SDKs retry throttles by default.

Per-partition limits (3,000 read units / 1,000 write units per second) have their own failure modes. Account-level quotas and the hard service limits are on the DynamoDB limits reference.

If you work against DynamoDB daily, DynoTable is a desktop client built for it.

By Dmitriy · Updated