DynamoDB Consistency: Eventual vs Strong Reads
Eventually consistent vs strongly consistent reads in DynamoDB — what each guarantees, cost and latency differences, and when you need strong consistency.
On this page
DynamoDB lets you choose, per read, whether you want the latest committed data or are willing to accept a slightly stale copy in exchange for lower cost and better availability. Understanding this choice is fundamental to both correctness and your bill.
This guide explains what each read mode guarantees, the cost and latency tradeoffs, and how to decide which one a given access pattern needs.
Why there are two modes at all
DynamoDB stores every item on multiple replicas across Availability Zones for durability. A write is acknowledged once it’s stored on a majority of those replicas — so writes themselves are durable and committed immediately.
But a read can be served by any replica. The other replicas converge to the latest value within a fraction of a second, but for that brief window they may serve the previous version. That gap is the entire reason eventual consistency exists — and why it’s faster and cheaper.
Eventually consistent reads (the default)
By default, reads are eventually consistent. The response might not reflect a write that completed moments ago, but the data will become consistent across all copies, typically within a second.
- Cost: half a read capacity unit per 4 KB (per item, rounded up).
- Latency: lowest — any replica can answer.
- Availability: highest — no need to reach a specific replica.
For the vast majority of access patterns this is the right default. A user reading their profile, a product catalog, a feed — none of these break if a write from 200 ms ago hasn’t propagated yet.
Strongly consistent reads
Set ConsistentRead = true to get a strongly consistent read. DynamoDB then returns a result reflecting all writes that received a successful response before the read — you always see the most recent committed data.
table.get_item(
Key={"PK": "USER#alice"},
ConsistentRead=True,
)
{
"TableName": "Users",
"Key": { "PK": { "S": "USER#alice" } },
"ConsistentRead": true
}
ConsistentRead is available on GetItem, BatchGetItem, Query, and Scan.
- Cost: a full read capacity unit per 4 KB — double the eventual cost.
- Latency: slightly higher, since the read must be served by a leader replica.
- Availability: lower — if the relevant replica is briefly unreachable, the read can fail with a
500where an eventual read might have succeeded.
Side-by-side
| Property | Eventually consistent | Strongly consistent |
|---|---|---|
| Default? | Yes | No (ConsistentRead=true) |
| Sees latest committed write | Usually, within ~1s | Always |
| RCU per 4 KB | 0.5 | 1 |
| Latency | Lowest | Slightly higher |
| Availability | Highest | Lower (needs leader replica) |
| Works on GSIs | Yes | No |
The 2× cost difference is real money at scale — see capacity and pricing for how RCUs map to your bill. Reading everything strongly “to be safe” can literally double your read costs for no benefit.
The GSI exception
Global Secondary Indexes only support eventually consistent reads. GSIs are maintained asynchronously: when you write to the base table, the propagation to the GSI happens in the background. There is no leader replica that can promise the index is current.
If an access pattern genuinely needs a strongly consistent read on certain attributes, you have two options:
- Read from the base table (strong reads allowed there).
- Use a Local Secondary Index (LSI), which does support strong reads because it shares the base table’s partitions. See secondary indexes for the LSI vs GSI tradeoffs.
When you actually need strong consistency
Reach for ConsistentRead=true only when a stale read would cause a correctness bug:
- Read-after-write where the same user immediately re-reads a value they just changed and must see it (e.g. confirming a setting saved).
- Conditional logic that branches on the very latest value — though for true atomicity, prefer a conditional write or a transaction over read-then-write.
- Sequential workflows where step 2 reads what step 1 wrote microseconds earlier and can’t tolerate lag.
For most reads — listings, dashboards, search, anything a human looks at — eventual consistency is correct and cheaper.
Strong consistency is not a substitute for atomicity
A common mistake is using a strongly consistent read to implement “check then act”:
read balance (strong) → if balance >= amount → write new balance
Even with a strong read, another writer can change the value between your read and your write. Strong consistency guarantees the read is current; it does not lock the item or make the read-modify-write atomic. For that you need a ConditionExpression on the write, or a transaction. Use strong reads for freshness, transactions for atomicity.
Practical guidance
- Default to eventual. Flip to strong only where a stale read is a bug.
- Never read GSIs strongly — it’s not an option, so design access patterns accordingly.
- Watch the bill. Auditing where you’ve set
ConsistentRead=trueis one of the easiest read-cost optimizations. - For decisions, prefer conditional writes to read-then-write, even with strong reads.
Seeing consistency behavior
Consistency lag is hard to reason about in the abstract because it’s measured in milliseconds and only matters under concurrency. When you’re modeling an access pattern, it helps to read the same item both ways and watch how a GSI trails the base table after a write. A native GUI like Tablyne lets you toggle ConsistentRead on a query and compare the results directly, which makes the tradeoff concrete rather than theoretical.
Consistency in DynamoDB is a per-read lever, not a table-wide setting. Default to eventual for cost and availability, switch to strong only where freshness is load-bearing, and remember that neither mode gives you atomicity — that’s what conditional writes and transactions are for.
Frequently asked questions
Are DynamoDB writes eventually consistent?
Writes are always durable and acknowledged only after being stored on a majority of replicas. The eventual-vs-strong distinction applies to reads — a write is committed immediately, but a later eventually consistent read might briefly miss it if it hits a lagging replica.
Can I do a strongly consistent read on a Global Secondary Index?
No. GSIs only support eventually consistent reads because they're maintained asynchronously. If you need a strongly consistent read on those attributes, you must read from the base table or a Local Secondary Index.
How much more do strongly consistent reads cost?
Twice as much. A strongly consistent read consumes a full read capacity unit per 4 KB, while an eventually consistent read consumes half a unit per 4 KB — so eventual reads are effectively half price.