DynamoDB for system design interviews
Open in the interactive app: practice, quiz, mock interview →In one minute
- DynamoDB is AWS's managed key-value and document database: you pick a partition key (and optionally a sort key), and it promises single-digit-millisecond reads and writes at almost any scale, with no servers to manage.
- Data is split into partitions by a hash of the partition key. Each partition is a three-replica Multi-Paxos group across availability zones, holding up to about 10 GB and serving up to 3,000 read units and 1,000 write units per second.
- Throughput is the design constraint. A table's capacity is spread across partitions, so a skewed key distribution throttles one partition while the table looks idle. Adaptive capacity and automatic splits soften this; they do not remove it.
- Choose it when access patterns are known, the scale is large or spiky, and you want zero operations. Avoid it when you need ad hoc queries, joins, large items (over 400 KB), or analytics over the whole table.
How it works
Keys and items
An item is a set of attributes up to 400 KB. The primary key is a partition key, optionally plus a sort key. Items sharing a partition key form an item collection, stored together and sorted by sort key, so Query can read a range (all orders for a customer between two dates) at up to 1 MB per page. Scan reads everything and is rarely the right answer.
Capacity
1 WCU is one write of up to 1 KB; 1 RCU is one strongly consistent read of up to 4 KB, or two eventually consistent ones. Provisioned mode reserves units per second, optionally auto scaled; on-demand, now the default and recommended mode, bills per request and absorbs up to double the previous peak instantly. A new on-demand table starts able to sustain 4,000 writes and 12,000 reads per second, and going past double the previous peak within 30 minutes can throttle, so pre-warm before a known spike (AWS docs). Every table also has a default quota of 40,000 read and 40,000 write units per second, adjustable on request (AWS docs).
Indexes, transactions, streams
A global secondary index (GSI) is a second table with a different key, maintained asynchronously. A local secondary index (LSI) re-sorts within the same partition key, must be created with the table, and caps each item collection at 10 GB. Transactions cover up to 100 items at double cost. Streams emit an ordered per-item change log retained 24 hours. Global tables replicate across regions, active-active. The default mode (multi-Region eventual consistency) replicates asynchronously, typically within a second, and resolves concurrent writes per item by last-writer-wins. You can instead create a table with multi-Region strong consistency: exactly three Regions (or two plus a witness), writes synchronously replicated before they return, strongly consistent reads anywhere and a recovery point of zero, at the cost of cross-Region write latency and no transactions, TTL or LSIs (AWS docs).
Down the stack
Layer 1The contract
A successful PutItem is durable in at least two of three availability zones before you get a 200: the leader acknowledges once a quorum of replicas has persisted the log record (DynamoDB paper, USENIX ATC 2022). A strongly consistent GetItem reflects every write acknowledged before it started. An eventually consistent read, the default, may miss a recent write; the docs promise no bound, only that a repeated read soon returns the newer item, and in practice the lag is usually far under a second. Reads are read-committed per item: you never see a write that did not succeed (AWS docs). Conditional writes (ConditionExpression) are atomic per item, which is how you build optimistic locking, idempotency keys and uniqueness. GSIs and streams are always eventually consistent; strongly consistent reads work only on the table and its LSIs. When you exceed capacity on a partition or table you get ProvisionedThroughputExceededException or ThrottlingException, which SDKs retry with backoff. Typical latency is 2 to 10 ms at p50 inside a region, with p99 under 20 ms for small items (hedge: varies with item size and region).
Layer 2The mechanism
Request routing. Every request lands on a fleet of stateless request routers. A router authenticates, looks up the partition map from a metadata service (cached heavily), hashes the partition key to find the partition, and forwards to that partition's leader. Routers also enforce global admission control: token buckets that track table-level capacity across the router fleet.
Partitions as replication groups. Each partition has three replicas in different zones. The replicas run Multi-Paxos: one leader, chosen by election, holds a lease. Writes go to the leader, which assigns a log sequence number, appends to its write-ahead log, and sends the entry to its peers; once a quorum (two of three, counting itself) has persisted the entry, it applies the write to its B-tree and acknowledges. Strongly consistent reads must go to the leader; eventually consistent reads can go to any replica. If the leader's lease lapses, a follower that sees no heartbeats starts an election, and the new leader serves no writes or strong reads until the old leader's lease has expired, so two leaders never both answer (DynamoDB paper).
Storage nodes. Each replica stores data in a B-tree keyed by the hash of the partition key plus sort key, alongside its replication log. Logs are archived to S3 continuously, which is what powers point-in-time recovery. When a storage node fails, the system first adds a log replica, a member that holds only recent log entries, which takes seconds to create; full B-tree replicas are rebuilt in the background. This keeps the write quorum healthy without waiting minutes to copy gigabytes.
Splits. A partition splits when it exceeds its size limit or when sustained traffic is concentrated on it. A split divides the hash range (or, for heat, picks a split point by observed key distribution) and the new partitions get their own capacity. A single partition key's items cannot be split by hash, which is why one key is ultimately bounded by one partition's 1,000 WCU and 3,000 RCU. DynamoDB also declines to split for heat when the traffic is on one item or walks the key range sequentially, since a split would not spread it, and splits take minutes rather than seconds (DynamoDB paper).
Adaptive and burst capacity. Early DynamoDB split provisioned throughput evenly across partitions, so a hot partition throttled while others idled. Burst capacity banks up to 300 seconds of unused throughput. Adaptive capacity lets a hot partition exceed its share, up to the per-partition maximum, while the table stays under its total, and split-for-heat then isolates the hottest ranges, down to a partition holding a single item. It will not split item collections when the table has an LSI (AWS docs). Internally the paper describes this as global admission control: each request router keeps a local token bucket and refills it from a central service every few seconds.
Layer 3The machine
A small GetItem crosses the network twice inside the region: client to router (often over a pooled HTTPS connection; TLS handshake costs are why connection reuse matters), and router to storage node. Each hop is sub-millisecond within a zone and about 0.5 to 1 ms across zones. A write adds a quorum round trip from the leader to a peer in another zone, plus a log append, typically to SSD where an fsync-equivalent costs tens to hundreds of microseconds. That adds up to the familiar 3 to 6 ms write.
Items are serialised in an internal binary format; attribute names count toward item size and capacity, so a 300-byte payload with long attribute names can tip a write from 1 WCU to 2 WCU. Reads are charged per 4 KB block, rounded up, and a Query sums the sizes of all items returned before rounding, which is why batching small items in one collection is cheaper than many GetItem calls.
Why it's built this way
- Multi-tenant predictability was the goal, so every partition has a hard ceiling and every table has admission control; one tenant cannot starve others on a shared storage node.
- Hard ceilings make skew painful, so adaptive capacity, burst credits and split-for-heat were added to let real, uneven workloads use the capacity they paid for.
- Zones fail independently, so three replicas across three zones with a two-of-three quorum survive a whole-zone loss without losing acknowledged writes.
- Copying a full replica takes minutes, so log replicas restore the quorum in seconds while the B-tree copy catches up.
- Hashing the partition key spreads load but destroys order across keys, so ordering exists only within one item collection, and global queries need GSIs or another system.
Diagram
sequenceDiagram
participant C as Client SDK
participant R as Request router
participant M as Partition metadata
participant L as Leader (AZ-a)
participant F1 as Follower (AZ-b)
participant F2 as Follower (AZ-c)
C->>R: PutItem(pk, item)
R->>R: auth + admission token bucket
R->>M: hash(pk) -> partition (cached)
R->>L: write
L->>L: assign LSN, append WAL
L->>F1: replicate entry
L->>F2: replicate entry
F1-->>L: ack
L->>L: quorum 2/3, apply to B-tree
L-->>R: OK
R-->>C: 200Worked example
A ticketing service stores seat holds: 30,000 writes per second at a big on-sale, 600-byte items, and 90,000 strongly consistent reads per second. That is 30,000 WCU and 90,000 RCU, so at least 30 partitions.
The first design keys on event_id with seat_id as sort key. For one concert every write hits one partition, capped at 1,000 WCU, so 29,000 writes per second throttle whatever the table's provisioning. Adaptive capacity cannot exceed the per-partition ceiling for one key.
The fix is write sharding: key event_id#shard with shard = hash(seat_id) mod 50, spreading a concert over 50 keys and up to 50,000 WCU. "All available seats" becomes 50 parallel Query calls, about 5 to 10 ms. Holds use a conditional write (attribute_not_exists(holder) OR expires_at < :now) so two buyers cannot hold one seat. At $0.625 per million on-demand writes in us-east-1 (AWS pricing), a two-hour peak costs about $135, far less than provisioning 30,000 WCU all month. Two traps remain: a fresh on-demand table sustains only 4,000 writes per second, so pre-warm it (warm throughput) to the on-sale peak beforehand, and request a quota increase if any table or index needs more than 40,000 units.
In the wild
- AWS, 2015: the metadata service overloads. On 20 September a short network blip made many storage servers ask the metadata service for their partition membership at once. Rapid adoption of global secondary indexes had made membership lists much larger, so responses exceeded the servers' timeout; servers took themselves out of service and retried, overloading the service further. Customer error rates peaked near 55 percent for about five hours, also hitting SQS, Auto Scaling and CloudWatch. AWS added metadata capacity, lengthened timeouts and planned to split the service (AWS).
- AWS, 2025: a DNS race empties the regional endpoint. DynamoDB's DNS automation has a planner that writes versioned plans and enactors that apply them. A delayed enactor applied a stale plan over a newer one, and cleanup of old plans then deleted every IP address for
dynamodb.us-east-1.amazonaws.com. DynamoDB errors lasted about three hours, and EC2's lease manager, which depends on DynamoDB, fell into congestive collapse, stretching the event to about 14.5 hours. AWS disabled the automation worldwide pending a fix (AWS).
Trade-offs
| Option | Strengths | Weaknesses | Choose when |
|---|---|---|---|
| DynamoDB | No ops, predictable latency at any scale, per-item conditional writes | Access patterns fixed up front, 400 KB items, hot-key ceilings, AWS lock-in | Known key-based access at large or spiky scale |
| Cassandra | Open source, multi-cloud, huge write throughput, tunable consistency | You run it: repairs, compaction, upgrades | Write-heavy time series on your own infrastructure |
| Aurora or Postgres | SQL, joins, ad hoc queries, rich transactions | Write scaling needs sharding; connection limits | Relational data, moderate scale, evolving queries |
| MongoDB | Flexible documents, secondary indexes, aggregation | Sharding and operations are on you unless using Atlas | Document data with varied query needs |
Pitfalls in production
- Hot partition key. One tenant or event takes all traffic and throttles at 1,000 WCU. Add a shard suffix (AWS docs); find culprits with CloudWatch Contributor Insights.
Scanas a query. It reads and bills the whole table. Model the pattern as aQueryon the table or a GSI.- GSI back-pressure. An under-provisioned GSI throttles base-table writes. Give GSIs at least the base write capacity, or use on-demand.
- Read-modify-write races. Use conditional expressions or a version attribute.
- Large items. Big blobs burn capacity on every update. Put payloads in S3 and keep a pointer.
Leadership lens
- Demand the list of access patterns before table design. The key schema is the query plan, and changing it later is a migration.
- Single-table design saves round trips but costs readability; choose it deliberately and document key conventions.
- Steady load favours provisioned with auto scaling; spiky or new workloads favour on-demand.
- Budget for GSIs, stream consumers and backups, which can cost as much as the base table, and give analytics an export path so nobody runs
Scanin production.
Check yourself
A table is provisioned with 10,000 WCU and is throttling at 1,200 WCU of total traffic. How?
Show answer
The traffic is concentrated on one partition key, and one partition cannot exceed about 1,000 WCU regardless of table capacity.
Why are eventually consistent reads half the price of strongly consistent ones?
Show answer
Any of the three replicas can serve them, while strongly consistent reads must go to the leader, so the system can spread them more cheaply.
What does a log replica buy during a node failure?
Show answer
It restores the two-of-three write quorum in seconds by holding only recent log entries, instead of waiting minutes to copy a full B-tree replica.
Why can a GSI slow down writes to the base table?
Show answer
Each base write must also be propagated to the GSI; if the GSI lacks capacity, DynamoDB throttles base writes to keep the index from falling too far behind.
Sources and further study
Primary
- Amazon DynamoDB pricing for on-demand capacity: current per-request prices, which AWS has changed before.
Systems docs
- DynamoDB global tables: how they work: the eventual and strong multi-Region modes and what each gives up.
- DynamoDB on-demand capacity mode: initial throughput, the double-the-peak rule and maximum throughput settings.
- DynamoDB burst and adaptive capacity: per-partition limits and isolation of hot items.
- DynamoDB warm throughput: pre-warming a table before a known spike.
Books
- Designing Data-Intensive Applications (1st edition), Martin Kleppmann, chapter 6 "Partitioning": hash partitioning, skew and hot spots, and secondary indexes by term.
- Database Internals, Alex Petrov, chapter 14 "Consensus": Paxos and Multi-Paxos, which each partition's replication group runs.
Other curricula
- donnemartin/system-design-primer: mentions DynamoDB as a store that supports both key-value and document access, within a general NoSQL overview.
- Azure Architecture Center: Understand data models: frames key-value stores as single-key atomic lookups that need redesign for value-based queries.
Watch
- Amazon DynamoDB Under the Hood: How We Built a Hyper-Scale Database (AWS re:Invent 2018): request routers, Paxos replication groups, partitions and adaptive capacity.
- Amazon DynamoDB Deep Dive: Advanced Design Patterns (AWS re:Invent 2018): Rick Houlihan's tour of key design, write sharding and single-table modelling.
Free resources
- Amazon DynamoDB: A Scalable, Predictably Performant, and Fully Managed NoSQL Database Service (USENIX ATC 2022): the paper on DynamoDB's real architecture, admission control and log replicas.
- Dynamo: Amazon's Highly Available Key-value Store (SOSP 2007): the ancestor design; useful for seeing what DynamoDB kept and what it changed.
- Designing partition keys to distribute your workload: official guidance on hot keys, burst and adaptive capacity.
- DynamoDB read consistency: exactly what eventually and strongly consistent reads guarantee.
- Service quotas in DynamoDB: item size, partition throughput, transaction and index limits.