How DynamoDB works internally
How DynamoDB partitions data, handles adaptive capacity, performs consistent reads, and auto-splits hot partitions without downtime.
The Interview Question
Interviewer: "Your team is running a DynamoDB table that suddenly starts returning
ProvisionedThroughputExceededExceptionfor a subset of keys. The table-level CloudWatch metrics show you are only using 40% of your provisioned capacity. Walk me through why this happens and what DynamoDB is doing internally to route and throttle these requests."
This question immediately separates candidates who have read the DynamoDB docs from those who understand its internal architecture. The interviewer wants to hear about partition-level throughput, request routing, adaptive capacity, and the burst bucket model. If you only say "hot partition," you get partial credit. If you explain the partition metadata system, the per-partition token bucket, and how adaptive capacity redistributes unused throughput, you nail it.
What to Clarify Before Answering
You: "Before I dive in, let me clarify the scope..."
- "Are we running in on-demand mode or provisioned mode? The throttling behavior differs significantly."
- "Is this a base table access or are we hitting a Global Secondary Index? GSIs have their own partition map."
- "Should I cover the request router layer and how it resolves partition key to storage node, or focus on the capacity model?"
- "Are we interested in the replication path too, including how consistent reads differ from eventually consistent reads?"
- "Is this a single-region table or a global table? Global tables add a cross-region replication layer."
Why this matters: DynamoDB's throttling behavior depends on the capacity mode, the access pattern (base table vs GSI), and the consistency level. A candidate who asks these questions demonstrates they know DynamoDB is not a monolithic database but a layered system with distinct routing, storage, and capacity management components.
The 30-Second Answer
DynamoDB is a fully managed, distributed key-value store built on top of a partitioned B-tree storage engine. When you write an item, the request router hashes your partition key to locate the correct storage partition, which lives on one of many storage nodes across three Availability Zones. Each partition stores up to 10 GB of data and supports up to 3,000 Read Capacity Units (RCUs) and 1,000 Write Capacity Units (WCUs). When a partition gets hot, DynamoDB uses adaptive capacity to borrow unused throughput from cold partitions. If that is not enough, it auto-splits the hot partition into two smaller partitions, redistributing the data and throughput without any downtime. Reads can be eventually consistent (hitting any of the three replicas) or strongly consistent (always hitting the leader replica that processed the most recent write).
The Architecture Overview
The architecture has three distinct layers. The request router is a stateless fleet of nodes that authenticates every request, looks up which storage partition owns the given partition key, and forwards the request. The partition metadata service maintains the mapping from key ranges to storage nodes, and the router caches this mapping aggressively. The storage layer consists of partitions, each replicated across three nodes in three Availability Zones using a Paxos-based consensus protocol.
I find this separation elegant because it means the router never stores data and the storage nodes never handle authentication. Each layer scales independently. When DynamoDB splits a partition, only the metadata mapping changes, and the router cache invalidates within milliseconds.
The request router fleet is massive. AWS runs thousands of router nodes that handle authentication, authorization, request validation, and routing. These routers are geographically distributed within each region and load-balanced. When your SDK sends a request, it hits a regional endpoint (like dynamodb.us-east-1.amazonaws.com) that resolves to one of these routers. The SDK maintains persistent HTTP/2 connections to avoid TLS handshake overhead on every request.
Partition Mapping and Request Routing
Every DynamoDB request starts at the request router. This is the component that turns a partition key into a physical storage location. Understanding this layer is essential because it explains why DynamoDB throttling is per-partition, not per-table.
When a DynamoDB table is created, it starts with a small number of partitions (typically 1-4 depending on the initial provisioned capacity). As the table grows in data size or throughput, DynamoDB adds partitions transparently. Each partition owns a contiguous range of the hash space. The partition metadata service maintains the canonical mapping of hash ranges to storage node IP addresses.
The router computes a hash of the partition key using an internal hash function (not MD5, not SHA, but a purpose-built consistent hash). This hash maps to a key range, and the metadata service tells the router which storage node owns that range.
The routing process is entirely deterministic. Given the same partition key, every router in the fleet computes the same hash and resolves to the same partition. This is critical for correctness: two concurrent writes to the same key must land on the same leader node. If routers disagreed on partition ownership, you would get split-brain writes.
Why this matters in production
When you see uneven throttling across a DynamoDB table, the root cause is almost always at this layer. The router correctly identifies the hot partition, but that partition has exhausted its per-partition throughput budget. Table-level metrics look fine because cold partitions are underutilized. I always check CloudWatch Contributor Insights first to identify which partition keys are consuming the most capacity.
The metadata cache on each router node refreshes on a timer and also invalidates on error. If a router sends a request to a storage node that no longer owns a partition (because a split happened), the storage node returns a redirect, and the router fetches fresh metadata. This redirect-and-refresh cycle completes in single-digit milliseconds, so partition splits are nearly invisible to clients.
Authentication happens at the router layer, not the storage layer. The router validates IAM signatures, checks permissions against the table's resource policy, evaluates VPC endpoint policies, and applies any fine-grained access control (attribute-level permissions). Only after all authorization checks pass does the router forward the request to the storage node. This means storage nodes never see unauthorized requests, reducing their attack surface.
Storage Nodes and the B-Tree Engine
Each DynamoDB partition is stored on a dedicated storage node as a B-tree backed by SSD storage. This is not a generic database engine. AWS built a purpose-specific storage engine optimized for key-value lookups with predictable latency.
The storage engine evolved from the original Dynamo paper (2007), which used a simple key-value store. Modern DynamoDB storage nodes use a heavily modified B-tree that supports:
- Point reads: O(log N) lookup by partition key + sort key.
- Range queries: O(log N + K) scan of contiguous sort key ranges within a partition.
- Conditional writes: Atomic check-and-write operations evaluated at the storage node level.
- Item-level TTL: Storage nodes track TTL timestamps and lazily delete expired items during background sweeps.
The write path is straightforward: every write first goes to the write-ahead log (WAL) on local SSD. Once the WAL entry is durable, the write is acknowledged. In the background, the storage engine merges WAL entries into the B-tree. This gives you O(log N) point reads and O(log N + K) range queries (where K is the number of items returned).
The B-tree stores items sorted by sort key within each partition key prefix. This is why Query operations on a sort key range are efficient: the items are physically adjacent on disk.
Why B-tree and not LSM tree?
DynamoDB chose B-trees over LSM trees (which Cassandra uses) because B-trees give more predictable read latency. LSM trees excel at write throughput but can spike read latency during compaction. For a managed service that promises single-digit millisecond reads, B-trees are the correct choice.
Each partition replicates to three storage nodes using Multi-Paxos. The leader node processes all writes and strong consistent reads. The two follower nodes receive replicated WAL entries and apply them asynchronously. This gives you:
- Write durability: A write is acknowledged only after 2 of 3 nodes persist the WAL entry. This means a single node failure never loses data.
- Read availability: Eventually consistent reads can go to any of the 3 replicas, giving you 3x the read throughput of a single node.
- Leader election: If the leader fails, one of the followers is elected within seconds using the Paxos protocol. The new leader must have the most up-to-date WAL before it can serve writes.
The B-tree pages are compressed before writing to SSD. DynamoDB uses a custom compression algorithm (not gzip, not LZ4) optimized for the access patterns of key-value data. Compression ratios of 2-4x are typical, which means a 10 GB partition limit translates to roughly 25-40 GB of uncompressed data capacity.
Each storage node runs multiple partitions. AWS does not disclose the exact hardware specs, but based on published papers, each node manages hundreds of partitions across NVMe SSDs. The node schedules I/O across partitions to prevent any single partition from monopolizing disk bandwidth.
Adaptive Capacity and Burst Credits
This is the mechanism that prevents naive hot-partition throttling from killing your application. I consider this one of the most important DynamoDB internals to understand because it directly explains the most common production issue: unexpected throttling.
DynamoDB assigns each partition a token bucket for read and write capacity. In on-demand mode, the bucket refills automatically based on observed traffic. In provisioned mode, the table-level throughput is divided across partitions, plus a burst allowance of 300 seconds of unused capacity.
The token bucket model works like this: each partition has a bucket that holds tokens. One token represents one capacity unit (RCU or WCU). Tokens are added at a fixed rate equal to the partition's base allocation. Tokens are consumed by each request. If the bucket is empty, the request is throttled. The bucket can hold up to 300 seconds worth of tokens, which is the burst capacity.
The adaptive capacity algorithm works in three stages:
-
Monitor: DynamoDB tracks consumed capacity per partition in real time. If a partition consistently exceeds its base allocation but the table has unused capacity, the system flags it.
-
Redistribute: The adaptive capacity controller shifts unused throughput from cold partitions to hot ones. This happens within minutes (sometimes faster). The total table throughput stays the same, but individual partitions can temporarily exceed their base allocation.
-
Split: If adaptive capacity cannot keep up (the hot partition needs more than the entire table's throughput), DynamoDB triggers an automatic partition split.
Adaptive capacity is not instant
There is a lag of 5 to 30 minutes before adaptive capacity kicks in. During that window, hot partitions will throttle. This is why burst credits exist: they cover the gap. If your burst credits are already depleted (because you had sustained hot traffic for more than 5 minutes), you get throttled immediately.
The burst bucket gives each partition 300 seconds of unused capacity. If a partition has a base of 1,000 WCUs and has been idle for 5 minutes, it accumulates 300,000 write credits. A sudden spike can consume these credits before throttling kicks in.
Here is a concrete example. Your table has 10 partitions provisioned at 10,000 WCUs total (1,000 per partition). A flash sale starts at noon:
- 12:00:00: Burst credits absorb the spike. No throttling.
- 12:00:30: Credits draining fast, but still available.
- 12:05:00: Burst credits exhausted on the hot partition. Throttling begins.
- 12:05:01 to 12:15:00: Adaptive capacity detects the hot partition and begins borrowing from cold partitions.
- 12:15:00: Adaptive capacity converges. Hot partition now has ~3,000 WCU budget (borrowed from 8 cold partitions).
- 12:30:00: If 3,000 WCU is still not enough, DynamoDB triggers a partition split.
The gap between 12:05 and 12:15 is where your application experiences throttling. This is the window you must design for.
Consistent Reads vs Eventually Consistent Reads
DynamoDB supports two read consistency models, and understanding the difference requires knowing how Paxos replication works inside each partition.
Every write in DynamoDB goes through a Paxos round. The leader proposes the write to the two followers. Once 2 of 3 nodes acknowledge the WAL entry, the write is committed and the leader responds to the request router. The third node eventually catches up, but there is a window (typically under 10ms) where it has stale data.
This replication lag creates two read options:
Eventually consistent reads route to any of the three replicas. The router picks the replica with the lowest latency (typically the one in the same AZ as the router). Because replication lag is usually under 10 milliseconds, eventually consistent reads return the latest data about 99.9% of the time. They cost 0.5 RCUs per 4 KB.
Strongly consistent reads always go to the partition leader. The leader checks its Paxos lease to confirm it is still the leader (avoiding stale reads during leader transitions), then returns the data. These cost 1.0 RCU per 4 KB, exactly double.
When to use strong consistency
I use strong consistency only when the application cannot tolerate a stale read. Shopping cart checkout, inventory decrement, financial transactions: these need strong reads. User profile display, analytics dashboards, content feeds: eventually consistent is fine and halves your read cost.
The leader knows it is still the leader because of a lease mechanism. The Paxos group renews leases periodically. If a leader's lease expires (because it is partitioned from the other nodes), it stops serving reads immediately. This prevents split-brain scenarios where two nodes think they are the leader.
DynamoDB also provides read-your-writes consistency within a single session when using the DynamoDB SDK with connection reuse. If your application writes to an item and then reads it with eventually consistent reads on the same connection, the SDK's connection affinity to a specific router (and that router's affinity to a specific AZ) makes it very likely you read from a replica that already received the write. This is not guaranteed by the API, but it is the observed behavior in practice.
For applications that need read-your-writes guarantees without paying the 2x cost of strong consistency, I recommend using a session token approach: after a write, store the write timestamp client-side and compare it against the item's timestamp on read. If the read returns a stale version, retry with strong consistency. This hybrid approach uses strong reads only when actually needed.
Global Tables and Cross-Region Replication
DynamoDB Global Tables replicate data across AWS regions with sub-second latency for active-active multi-region architectures. This is DynamoDB's answer to multi-region availability, and it is the simplest managed cross-region replication I have used.
Global Tables operate on a simple principle: every region has a full, writable replica of the table. There is no primary region. Any region can accept writes at any time. Changes propagate asynchronously to all other regions.
Global Tables use DynamoDB Streams as the replication mechanism. Every write in one region generates a stream record that is consumed by a replication process and applied to the other regions.
Conflict resolution uses last-writer-wins (LWW) based on timestamps. Each item carries a aws:rep:updatetime attribute with microsecond precision. When two regions write to the same item concurrently, the write with the later timestamp wins. This is simple but has a critical limitation: if clocks are skewed between regions, the "wrong" write can win.
Last-writer-wins is not safe for counters
If Region A increments a counter from 10 to 11, and Region B increments it from 10 to 11 at the same time, LWW picks one write. The result is 11, not 12. If you need distributed counters or CRDTs, DynamoDB Global Tables are the wrong choice. Use a coordination service or move to a conflict-free data model.
Replication lag is typically 500ms to 2 seconds, depending on the distance between regions and the write volume. During normal operation, this is transparent to applications. During a regional outage, you failover to another region and accept that the last few seconds of writes may not have replicated.
Global Tables version 2 (the current version) automatically manages the replication infrastructure. You do not create or manage DynamoDB Streams directly. AWS allocates dedicated stream capacity for cross-region replication, separate from any streams you configure for your own Lambda triggers. This means enabling Global Tables does not compete with your application's stream consumers.
One subtlety I find important: Global Tables require that all tables in the group have the same primary key schema, same provisioned capacity settings (or all on-demand), and the same encryption configuration. You cannot add a GSI in one region and not the others. The tables are logically identical replicas, and DynamoDB enforces this at the schema level.
Auto-Scaling and Partition Splitting
DynamoDB automatically splits partitions when they get too large (>10 GB) or too hot (sustained throughput exceeds the partition limit). This is one of the most impressive internal mechanisms because it happens with zero downtime.
DynamoDB Streams and Change Data Capture
Before covering splits, it is important to understand DynamoDB Streams, because they power both Global Tables replication and the split coordination mechanism.
DynamoDB Streams captures a time-ordered sequence of item-level modifications to any DynamoDB table. Each stream record contains the partition key, old item image, new item image (or both), and a sequence number. Streams are sharded by partition, and each shard maps 1:1 to a table partition. When a partition splits, the stream shard also splits.
Stream consumers (Lambda triggers, Kinesis Data Streams adapters, or custom consumers) process records in order within each shard. This guarantees that all modifications to the same partition key are processed in the order they occurred. Cross-partition ordering is not guaranteed.
Streams are the backbone of DynamoDB's async features
Global Tables, point-in-time recovery (PITR), and Lambda triggers all build on DynamoDB Streams. Understanding streams is essential for debugging replication lag, Lambda cold starts on DynamoDB triggers, and PITR recovery point objectives.
The Split Algorithm
The split process works like this:
-
Detection: The auto-capacity controller monitors per-partition throughput and storage size. When a partition exceeds thresholds, it triggers a split.
-
Preparation: Two new partitions are created on fresh storage nodes. The key range of the old partition is divided at the midpoint (by hash space, not by item count).
-
Data copy: Items are copied from the old partition to the two new partitions. During this phase, the old partition continues to serve reads and writes normally.
-
Cutover: The metadata service atomically updates the partition map. Request routers invalidate their cached mapping. New requests go to the new partitions. The old partition drains any in-flight requests.
-
Cleanup: The old partition is decommissioned and its storage reclaimed.
The split point is not chosen randomly. DynamoDB analyzes the traffic pattern to find a split point that evenly divides both the data volume and the request rate. For heat-based splits, the system identifies the "hot" key ranges and splits to isolate them. For size-based splits, the midpoint of the hash range is used.
Split operations are not instant. The data copy phase can take seconds to minutes depending on partition size. But because the old partition continues serving during the copy, clients experience zero downtime. The only observable effect is a brief metadata cache invalidation that adds a single-digit millisecond blip to the first request after the cut-over.
Why you cannot control partition splits
DynamoDB does not expose partition count or split operations to users. This is intentional. AWS wants the system to be self-managing. But it means you cannot force a split for a hot key. The only tool you have is data modeling: spread your access pattern across more partition keys.
Transactions and Conditional Writes
DynamoDB supports ACID transactions across up to 100 items in a single table or across tables. Transactions use a two-phase protocol internally.
In the prepare phase, the transaction coordinator sends a prepare request to every partition involved. Each partition checks the condition expressions (if any) and acquires a lock on the affected items. If all partitions respond with "prepared," the coordinator moves to the commit phase, where each partition durably applies the changes.
If any partition fails to prepare (condition check fails, item locked by another transaction, capacity exceeded), the entire transaction is rolled back. No items are modified.
// Pseudocode: DynamoDB Transaction Commit Protocol
function TransactWriteItems(items):
// Phase 1: Prepare
for each item in items:
partition = resolvePartition(item.key)
result = partition.prepare(item, lockTimeout=5s)
if result == FAILED:
rollback(allPreparedPartitions)
throw TransactionCanceledException
// Phase 2: Commit
for each preparedPartition:
preparedPartition.commit()
return SUCCESS
Transactions cost 2x the capacity of individual operations. A TransactWriteItems with 5 items costs 10 WCUs (2 per item). This is because each item is written twice: once to the transaction log and once to the actual storage.
Isolation Levels
DynamoDB transactions provide serializable isolation for the items involved in the transaction. But reads outside a transaction are not isolated from concurrent transactions. If you read an item with GetItem while a TransactWriteItems is in progress, you might see the old value or the new value, depending on timing. You will never see a partial update (some items committed, others not), but you can see pre-commit or post-commit state for individual items.
This is different from relational database transactions where you can set isolation levels like READ COMMITTED or REPEATABLE READ. DynamoDB gives you exactly one level: serializable for transactional operations, eventually consistent for everything else.
Transactional reads (TransactGetItems) give you a consistent snapshot of multiple items. If you need to read 5 items and guarantee they are all from the same point in time, TransactGetItems is the way to do it. The cost is 2x the RCUs of individual GetItem calls.
Transaction Limits and Gotchas
Transactions are limited to 100 items per call, 4 MB total request size, and all items must be in the same AWS region. You cannot mix items from different regions in a Global Table transaction. Each item in a transaction can be from a different table, which is useful for maintaining cross-table invariants.
One gotcha: if two transactions touch the same item, one will fail with TransactionConflictException. DynamoDB does not queue or retry conflicting transactions. Your application must handle this with retry logic and exponential backoff.
Another common mistake is nesting transactions. DynamoDB does not support TransactWriteItems inside another transaction. If your business logic requires multi-step transactional workflows, you need to implement the Saga pattern or use Step Functions to orchestrate individual transactions.
Idempotency with Client Tokens
Every TransactWriteItems call accepts an optional ClientRequestToken. If you retry a transaction with the same token within 10 minutes, DynamoDB returns the original result without re-executing the transaction. This is critical for exactly-once semantics in distributed systems where network failures can cause duplicate requests.
I always set a client token on transactions that modify financial data or counters. Without it, a network timeout followed by a retry can double-apply the transaction.
DynamoDB Accelerator (DAX)
DAX is a fully managed, in-memory cache that sits in front of DynamoDB. It speaks the DynamoDB API, so you swap the DynamoDB client for a DAX client and your reads start hitting cache. No application logic changes needed.
Architecturally, DAX is a cluster of EC2 instances running in your VPC. You choose the instance type and the number of nodes (3 to 10 for production). The primary node handles writes. Replica nodes handle reads. If the primary fails, a replica is promoted automatically.
DAX maintains two separate caches:
- Item cache: Stores individual items from
GetItemandBatchGetItemcalls. Default TTL is 5 minutes. - Query cache: Stores full result sets from
QueryandScanoperations, keyed by the exact parameters. Default TTL is 5 minutes.
Writes go through DAX to DynamoDB (write-through). DAX updates its item cache after a successful write, but the query cache is only invalidated by TTL expiration. This means a PutItem followed by a Query can return stale results if the query result was cached before the write.
DAX is not appropriate for strong consistency
DAX only supports eventually consistent reads. If you send a strongly consistent read through DAX, it passes through to DynamoDB directly, bypassing the cache entirely. If your application relies heavily on strong consistency, DAX provides no benefit.
DAX clusters run inside your VPC, so there is no public internet hop. Typical cache-hit latency is 200-400 microseconds, roughly 10x faster than a DynamoDB eventually consistent read. For read-heavy workloads with predictable access patterns, DAX can reduce your read costs by 90% and your p99 latency by an order of magnitude.
One thing to watch out for: DAX does not invalidate the query cache on writes. If you write an item and then immediately run a Query that should include it, the cached query result will not contain the new item until the TTL expires. This is a common source of bugs in applications that mix writes and queries through DAX.
I recommend DAX for read-heavy workloads where the access pattern is predictable (same keys read repeatedly) and eventual consistency is acceptable. Gaming leaderboards, product catalog lookups, and session stores are good fits. Real-time analytics dashboards or write-heavy workloads are not.
What Happens When Things Break
DynamoDB is designed to self-heal from most failure scenarios. But understanding the failure modes helps you design resilient applications and answer interview questions about distributed system tradeoffs.
| Failure | What Happens | How to Detect | How to Fix |
|---|---|---|---|
| Storage node crash | Paxos group elects new leader in 1-3 seconds. Writes stall briefly. No data loss because 2/3 nodes still have the data. | SystemErrors metric spikes, Paxos failover log events | Automatic. DynamoDB replaces the failed node and re-replicates. |
| Network partition between replicas | Leader continues accepting writes if it has quorum (2/3 nodes reachable). Isolated replica falls behind. | Replication lag increases, eventually consistent reads may be stale | Automatic. When the partition heals, the lagging replica catches up from the WAL. |
| Hot partition throttling | Requests to that partition get ProvisionedThroughputExceededException. Other partitions are unaffected. | ThrottledRequests metric in CloudWatch, Contributor Insights shows hot key | Redesign partition key for better distribution, enable auto-scaling, or switch to on-demand mode. |
| Metadata service unavailable | Router uses stale cache. New requests still route to correct partitions (until a split happens). If cache is cold, requests fail. | 5xx errors from DynamoDB API, internal service error responses | Automatic recovery. Metadata service is highly available and this is extremely rare. |
| Region-wide outage | Global Tables serve traffic from surviving regions. ~1-2 seconds of writes may be lost on failover. | AWS Health Dashboard, Route 53 health checks | Switch DNS to healthy region. Accept LWW resolution for any conflicting writes. |
Performance Characteristics
DynamoDB's performance is remarkably consistent because AWS controls the entire stack: hardware, storage engine, replication, and routing. There are no noisy neighbors at the storage layer (each partition runs on dedicated resources).
| Operation | Latency (p50) | Latency (p99) | Throughput Limit | Cost (on-demand) |
|---|---|---|---|---|
| GetItem (EC read) | 1-2 ms | 5-10 ms | 3,000 RCU per partition | $0.25 per million reads |
| GetItem (strong read) | 2-4 ms | 10-20 ms | 3,000 RCU per partition | $0.25 per million reads |
| PutItem | 3-5 ms | 10-20 ms | 1,000 WCU per partition | $1.25 per million writes |
| Query (100 items) | 5-15 ms | 20-50 ms | Limited by page size (1 MB) | Varies by data scanned |
| Scan (full table) | Seconds to minutes | Depends on table size | 1 MB per page, parallel scan available | Scans entire table, expensive |
| BatchGetItem (25 items) | 5-15 ms | 30-80 ms | Limited by individual partition throughput | Per-item pricing |
| TransactWriteItems | 10-25 ms | 50-100 ms | 2x cost of individual writes | Double WCU cost |
| GSI propagation | 100-500 ms | 1-5 seconds | Async, no SLA | Included in base cost |
The 10 GB partition limit is real
Each partition holds a maximum of 10 GB. If a single partition key prefix accumulates more than 10 GB (for example, a sort key collection under one partition key), DynamoDB cannot split it further because all items share the same partition key. This is a hard limit. Design your data model to keep per-partition-key data well under 10 GB.
The latency characteristics of DynamoDB are remarkably stable. Unlike databases with background processes that cause periodic latency spikes (Cassandra's compaction, PostgreSQL's vacuum), DynamoDB manages these processes transparently. The partition split mechanism avoids I/O contention by copying data to new partitions on fresh storage nodes. The result is that p99 latency stays flat even under sustained load, which is rare for distributed databases.
One important subtlety: DynamoDB DAX (DynamoDB Accelerator) adds an in-memory caching layer in front of DynamoDB. DAX reduces read latency to microseconds for cache hits. But DAX caches are eventually consistent only (even for items written through DAX), so it does not replace strong consistent reads. Use DAX for read-heavy, latency-sensitive workloads where eventual consistency is acceptable.
How This Compares to Alternatives
The choice between DynamoDB and its alternatives comes down to three factors: operational overhead, query flexibility, and cost model. This table covers the key dimensions.
| Feature | DynamoDB | Cassandra | MongoDB | Redis |
|---|---|---|---|---|
| Data model | Key-value / document | Wide-column | Document (BSON) | Key-value / data structures |
| Consistency | EC default, strong optional | Tunable (ONE to ALL) | Strong (single-doc), causal (sessions) | Strong (single-node), EC (cluster) |
| Scaling | Fully managed, auto-split | Manual cluster management | Auto-sharding (since 3.6) | Cluster with hash slots |
| Write latency | 3-5 ms | Sub-ms (local commit) | 1-5 ms | Sub-ms (in-memory) |
| Read latency | 1-2 ms (EC) | 1-5 ms (depends on CL) | 1-3 ms | Sub-ms (in-memory) |
| Durability | 3-way Paxos replication | Configurable RF (typically 3) | Journaling + replica sets | AOF + RDB snapshots |
| Operations burden | Zero (fully managed) | High (JVM tuning, compaction, repairs) | Medium (sharding, oplog management) | Low-Medium (memory management, persistence config) |
| Cost model | Per-request or provisioned capacity | Infrastructure cost (self-hosted) | Per-request (Atlas) or self-hosted | Per-node (ElastiCache) or self-hosted |
| Best for | Serverless, predictable key-value access | High write throughput, time-series | Flexible queries, aggregations | Caching, real-time leaderboards |
I reach for DynamoDB when I need a zero-ops database with predictable single-digit millisecond latency and I can model my access patterns upfront. I switch to Cassandra when I need raw write throughput on infrastructure I control, to MongoDB when I need flexible querying, and to Redis when I need sub-millisecond latency and can tolerate data fitting in memory.
The DynamoDB killer feature
The single biggest advantage of DynamoDB is not the speed, the durability, or the scaling. It is the operational overhead: zero. No OS patches, no JVM tuning, no backup scripts, no compaction tuning, no disk management, no replica lag monitoring. For teams without dedicated DBAs, this eliminates an entire category of production incidents. I have seen DynamoDB tables run for years without a single operational intervention.
Interview Cheat Sheet
These are the key talking points to memorize. In an interview, you will not have time to explain every detail. Pick the points that match the interviewer's question and go deep on those.
-
When asked about partitioning: "DynamoDB hashes the partition key to assign items to partitions. Each partition supports up to 3,000 RCUs and 1,000 WCUs. Hot partitions get extra throughput from adaptive capacity, and DynamoDB auto-splits when sustained hot traffic exceeds what borrowing can cover."
-
When asked about consistency: "DynamoDB defaults to eventually consistent reads, which can hit any of the three replicas. Strong consistent reads always go to the Paxos leader, which verifies its lease before responding. Strong reads cost 2x the RCUs."
-
When asked about throttling: "Throttling happens at the partition level, not the table level. A table can show 40% utilization overall while one partition is 100% throttled. The fix is better partition key design, not more provisioned capacity."
-
When asked about replication: "Each partition is replicated to 3 nodes across 3 AZs using Multi-Paxos. Writes need 2/3 acks for durability. Leader election takes 1-3 seconds on failure."
-
When asked about Global Tables: "Global Tables use DynamoDB Streams for async cross-region replication. Conflict resolution is last-writer-wins based on timestamps. Replication lag is typically under 2 seconds."
-
When asked about storage: "DynamoDB uses a B-tree storage engine on SSDs with a write-ahead log. B-trees give predictable read latency unlike LSM trees. Each partition holds up to 10 GB."
-
When asked about auto-splitting: "DynamoDB splits partitions when they exceed 10 GB or sustained throughput limits. The split is transparent: old partition serves traffic during copy, metadata update is atomic, router caches invalidate immediately."
-
When asked about on-demand vs provisioned: "On-demand mode auto-scales to 2x the previous peak and charges per request. Provisioned mode with auto-scaling is 5-7x cheaper at steady-state but requires capacity planning. Use on-demand for unpredictable workloads, provisioned for predictable ones."
-
When asked about transactions: "DynamoDB supports ACID transactions across up to 100 items in a single table or across tables. Transactions use a two-phase commit protocol and cost 2x the capacity of individual operations."
-
When asked about GSIs: "Global Secondary Indexes are separate, fully partitioned tables that DynamoDB keeps in sync asynchronously. GSI updates can lag by up to a few seconds. GSIs have their own throughput limits and can throttle independently of the base table."
-
When asked about data modeling: "DynamoDB requires you to know your access patterns before you design the schema. Use single-table design with composite sort keys to support multiple query patterns. Overloaded GSIs let you query the same data by different attributes. If you do not know your access patterns upfront, DynamoDB is the wrong choice."
-
When asked about cost optimization: "Use eventually consistent reads (50% cheaper), keep item sizes under 4 KB, use batch operations to amortize request overhead, enable auto-scaling with 50-70% target utilization, and use TTL for automatic data cleanup instead of explicit deletes."
Test Your Understanding
Quick Recap
These are the 8 facts I want you to walk away with. Each one is independently useful in an interview.
-
DynamoDB routes every request through a stateless request router that hashes the partition key to locate the correct storage partition using a cached metadata map.
-
Each partition stores data in a B-tree on SSDs with a write-ahead log, replicated to 3 nodes across 3 AZs using Multi-Paxos for durability.
-
Throttling happens at the partition level (3,000 RCU, 1,000 WCU per partition), not the table level, which is why table-wide metrics can look healthy while individual keys get throttled.
-
Adaptive capacity borrows unused throughput from cold partitions and redirects it to hot ones, but it takes 5-30 minutes to converge.
-
Strongly consistent reads always go to the Paxos leader (which verifies its lease), while eventually consistent reads go to any replica and cost half the RCUs.
-
Global Tables replicate asynchronously across regions using DynamoDB Streams with last-writer-wins conflict resolution and 500ms to 2 second replication lag.
-
Partition splits happen automatically and transparently: data is copied to new partitions while the old one continues serving, and the metadata switch is atomic.
-
On-demand mode scales instantly to 2x the previous peak; beyond that, DynamoDB needs time to provision, so pre-warming is necessary for massive spikes.
-
Transactions use a two-phase commit across partitions with 2x capacity cost, and are designed for multi-item atomicity (not single-item conditional writes, which use cheaper condition expressions).
-
DynamoDB Streams capture a time-ordered sequence of changes and power Global Tables, Lambda triggers, and PITR. Stream shards map 1:1 to table partitions.
Related Concepts
These topics connect directly to DynamoDB internals. Understanding them deepens your ability to reason about trade-offs in system design interviews.
- Consistent Hashing: The foundation of DynamoDB's partition mapping, also used by Cassandra and most distributed databases.
- Paxos Consensus: The replication protocol DynamoDB uses for leader election and write durability across its three-node partition groups.
- LSM Trees vs B-Trees: Understanding why DynamoDB chose B-trees (predictable reads) while Cassandra chose LSM trees (high write throughput) is key to choosing between them.
- CAP Theorem: DynamoDB is a CP system for strongly consistent reads and an AP system for eventually consistent reads, making it a rare example that offers both modes.
- Write-Ahead Logging: The crash recovery mechanism DynamoDB uses to ensure no acknowledged write is ever lost, even during node failures.