How much throughput does a new DynamoDB on-demand table get?
A brand-new On-demand capacity 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
Hot partition involved:
| Offered (writes/s) | Achieved | Throttled requests |
|---|---|---|
| 1,000 | 1,000 | 0 |
| 2,000 | 2,000 | 0 |
| 3,000 | 3,000 | 0 |
| 4,000 | 4,000 | 0 |
| 5,000 | 4,132 | 25,992 |
| 6,000 | 4,131 | 55,966 |
| 8,000 | 4,134 | 115,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 Exponential backoff). 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
Eventually consistent read GetItems (~1 KB, 0.5 read units each):
| Offered (reads/s) | Achieved | Throttled requests |
|---|---|---|
| 4,000 | 4,000 | 0 |
| 8,000 | 7,941 | 0 |
| 12,000 | 11,119 | 0 |
| 16,000 | 12,762 | 0 |
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:
| Wave | Started | Achieved writes/s, minute by minute |
|---|---|---|
| 1 | 06:06 UTC | 4,019 → 4,001 → 4,001 → 3,999 → 3,998 → 4,000 → 4,000 → 4,000 |
| 2 | 06:15 UTC | 5,046 → 5,000 → 4,996 → 4,990 → 4,991 → 4,998 → 4,992 → 4,993 |
| 3 | 06:24 UTC | 5,046 → 4,973 → 4,991 → 4,981 → 4,983 → 4,989 → 4,993 → 5,978 |
| 4 | 06:32 UTC | 7,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.
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
ACTIVEin 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.










