Trade-offs · Production decisions
Strong vs eventual vs causal consistency
How to choose strong, causal or eventual consistency for each operation, the numbers that change the answer, and what breaks with each.
Asked at: SDE-2Senior
The decision
When data has copies on many servers, a read can show the newest write, or an older one. A consistency level is the promise about which one you get. Strong consistency acts as if there is one copy: after a write finishes, every read shows it. Causal consistency promises that nobody sees an effect before its cause, such as a reply before its question. Eventual consistency promises only that the copies agree after writes stop, with no time limit. You choose the level for each operation, not for the whole system.
Choose strong consistency when
- A wrong answer costs money or trust. Examples are a seat count, a wallet balance and a stock count.
- The code reads a value and then decides something from it, such as "if the seat is free, book it". A stale read makes a wrong decision.
- A name or a key must be unique across all users, such as a username.
- Writes are few and the data is small, so one leader can serve the reads that need the newest value.
Choose causal consistency when
- Items refer to each other: replies to comments, messages in a chat, an edit made after reading a document.
- You need "cause before effect" but not one global order for all items.
- Strong is too slow because users are far apart, and eventual shows orphans (a reply with no question).
Choose eventual consistency when
- An old value is harmless for some seconds. Examples are like counts, feeds, search results and product listings.
- The service must keep answering when part of the network breaks.
- Users in many regions need fast reads from a copy near them.
The numbers that change the answer
Three numbers decide most cases: the cost of a wrong answer, the extra time for a strong operation, and the read load on the leader.
| Number | Value | Label |
|---|---|---|
| Disk write | 1 ms | Assumption |
| Local read | 2 ms | Assumption |
| Round trip, Mumbai to Chennai | 30 ms | Assumption |
| Leader | 8 CPU cores = 8,000 ms of work per second | Assumption |
Time. A write that waits for a far follower takes 1 + 30 + 1 = 32 ms. This is the worst case, with the steps in a row. An asynchronous write takes 1 ms. A strong read from Chennai goes to the leader in Mumbai: 2 + 30 = 32 ms. A local read takes 2 ms. So strong is 32 times slower for writes and 16 times slower for reads, in this example.
Load. Worked example: a food-delivery app shows order status. Assumption: 10,000 status reads per second at peak, and each read costs 2 ms of CPU.
- Work = 10,000 x 2 ms = 20,000 ms per second.
- The leader has 8,000 ms per second. That is 20,000 / 8,000 = 2.5 times too much.
- So status reads cannot all be strong. Spread them over 4 followers: 20,000 / 4 = 5,000 ms each, which is 62.5% of a server. Assumption: we plan for at most 70% busy. This ignores the small cost of applying writes.
Causal wait. Assumption: the follower of the questions store is 2 seconds behind, and the follower of the replies store is 0.4 seconds behind. A reply shows up 2 - 0.4 = 1.6 seconds before its question. Causal consistency holds the reply back for up to 1.6 seconds. That is a small delay, and no orphan appears.
Price. A cited fact: in Amazon DynamoDB, eventually consistent reads cost half as much as strongly consistent reads, and eventual is the default. Strong costs money, not only time (see Sources).
What breaks with each choice
Strong.
- During a network break, the side that cannot reach the leader must refuse requests. Fallback: refuse only the risky operations (booking) and keep safe ones (browsing) on eventual reads.
- The leader becomes the bottleneck, as the load example shows. Fallback: send only the reads that need the newest value to the leader.
- Latency grows with distance. Fallback: put the leader near most users. Strong consistency across the world is possible but needs special design. The Spanner paper describes one such database, and its time API called TrueTime.
Eventual.
- A decision made on an old read is wrong. For example, two users see "1 seat left" and both book. Fallback: make the write check again, with a conditional update, which changes the row only if it still has the value you read.
- A user saves and then sees the old value. Fallback: read-your-writes, which sends that user's next reads to the leader for a short time.
Causal.
- Every message must carry the position of what it depends on. One forgotten hop breaks the promise silently.
- A store that is far behind makes the reader wait. Fallback: set a wait limit, and hide the new item until the cause arrives.
What it costs
- Money. Strong reads need more leader capacity or, on a managed database, a higher price. The DynamoDB example is 2 times per read.
- People. Assumption: one engineer-week to add read-your-writes to a service that has none.
- Changing your mind. Moving one operation from eventual to strong is a small change: send its reads to the leader, and check the leader has capacity. Moving from strong to eventual is also small. The costly change is a design that assumed fresh reads in many places, because you must find each one. Write the level next to each operation from the start.
How each level answers
SDE-1: Strong means every read shows the latest write. Eventual means copies agree after some time. Strong is slower.
SDE-2: I pick the level for each operation. Booking a seat is strong, because a wrong read sells a seat twice. The seat count on the search page is eventual, because it can be seconds old.
Senior: A strong write across two cities costs about 32 ms against 1 ms. 10,000 strong reads per second need 2.5 leaders of CPU, so only booking reads go to the leader. When the link breaks, the far side refuses bookings and keeps serving search. A conditional write is the last guard.
Staff: I keep a table of every operation, its level and the cost of a wrong answer, and I review it in design review. I start with eventual reads for browsing and strong only for money, then move an operation up only when a measured wrong decision appears. I measure those wrong decisions, follower lag at the 99th percentile, and requests refused during breaks. If wrong decisions stay near zero and the leader stays under plan, the levels are right. The platform team owns the read-your-writes library.
Say it in the interview
I choose the level for each operation. A seat booking is strong, because a stale read sells a seat twice, and I accept 32 ms instead of 1 ms for it. Search counts are eventual, so followers serve them, and in a network break the side without the leader refuses bookings but keeps showing search.
Common mistakes
- Saying "our system is CP" or "AP" and stopping. One system can refuse bookings and still serve search in the same break. Name the level for each operation.
- Using strong everywhere to be safe. The leader runs out of capacity, and far users wait 30 ms or more on every call.
- Using eventual for check-then-act. A stale read makes the check wrong. Add a conditional write or move that read to the leader.
Sources
- Amazon DynamoDB, read consistency: eventual is the default, and eventually consistent reads cost half as much as strongly consistent reads. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html (opens in a new tab) (checked 26 Oct 2026)
- Google Spanner paper (OSDI 2012), abstract: the first system to distribute data at global scale and support externally consistent distributed transactions, built on TrueTime, a time API that exposes clock uncertainty. https://www.usenix.org/conference/osdi12/technical-sessions/presentation/corbett (opens in a new tab) (checked 26 Oct 2026)
- All latency, CPU and lag figures above are assumptions for teaching, not measurements.
Understand the trade-off. Practise explaining your choice.
In an AI mock interview, the interviewer can push on a choice like this one: it changes a number and asks if your answer still holds.