Consistency Models: Strong, Eventual and Causal
Consistency models explained: linearizability, sequential, causal, read-your-writes and eventual consistency, with examples of where each fits.
A consistency model is a contract between a data store and its users about what reads can return when data is replicated and updated concurrently. Stronger models are easier to program against but cost latency and availability; weaker models are faster and more available but push complexity into the application.
From strongest to weakest
| Model | Guarantee | Typical cost |
|---|---|---|
| Linearizable (strong) | Every operation appears to happen at a single instant between its start and end; reads see the latest completed write, globally | Coordination (a leader or quorum) on every operation; unavailable on the minority side of a partition |
| Sequential | All clients see all operations in the same order, consistent with each client's own order, but not necessarily real time | Still needs agreement on a total order |
| Causal | Operations that are causally related (a reply after the post it answers) are seen in that order by everyone; unrelated ones may differ | Tracking dependencies (e.g. vector clocks); available during partitions |
| Read-your-writes | A client always sees its own earlier writes | Session stickiness or version tokens |
| Monotonic reads | A client never sees data go back in time | Stick a session to one replica, or track a version |
| Eventual | If writes stop, all replicas eventually converge | Cheapest; stale and out-of-order reads are possible |
What goes wrong with weak consistency
Imagine asynchronous replication from a primary to read replicas, with a lag of a few hundred milliseconds:
Other anomalies under eventual consistency:
- Non-monotonic reads: refreshing a page shows a comment, then on the next refresh it disappears, because the second read hit a staler replica.
- Causality violations: you see a reply before the message it replies to.
- Lost updates: two concurrent writes to different replicas, and one silently overwrites the other (last-write-wins).
Worked example: who sees what, right after a write
The author updates a value from v1 to v2 at t = 0, and the replica needs 3 ticks to catch up. The levels differ only in what reads return during those 3 ticks:
| Level | Author reads (t = 1) | Another user reads (t = 1) | After the replica syncs (t ≥ 3) |
|---|---|---|---|
| Strong | v2 | v2 (reads go to the leader or wait for replicas) | v2 / v2 |
| Read-your-writes | v2 (the author's reads are routed to fresh data) | v1 (may be stale) | v2 / v2 |
| Eventual | v1 (even the author may see stale data) | v1 | v2 / v2 |
Stronger levels send reads to the leader or wait for replicas to confirm, which costs latency and availability; weaker levels read the nearest replica and may be stale. Pick the weakest model the feature tolerates: read-your-writes is often the sweet spot for profile edits and posts.
Practical techniques
- Read your own writes: after a user writes, route their reads to the primary for a short window, or return a version (an LSN or timestamp) with the write and have replicas wait until they've caught up to it.
- Monotonic reads: pin a user's session to one replica (by hashing the user id).
- Quorums: with N replicas, writing to W and reading from R where R + W > N guarantees a read overlaps the latest write. See replication.
- Conflict handling for concurrent writes: last-write-wins (simple, loses data), version vectors that surface conflicts to the app, or CRDTs, data types like counters and sets that merge automatically. See clocks and ordering.
Choosing a model per feature
| Data | Model that fits | Why |
|---|---|---|
| Account balance, inventory count, unique usernames | Linearizable | Two people must not both get the last seat or the same username |
| A user editing their own profile or settings | Read-your-writes | Seeing your own change disappear looks like a bug |
| Comments and replies, chat messages | Causal | Replies must not appear before what they answer |
| Like counts, view counts, recommendations | Eventual | Being a few seconds behind is invisible to users |
| Search index, analytics dashboards | Eventual, with a known lag | Updated asynchronously from the source of truth |
Strong consistency isn't free, but neither is weak consistency: every anomaly you allow becomes a bug someone has to reason about. Use strong consistency for invariants that matter, and weaker models where staleness is harmless.
Where it’s used
Offer externally consistent (linearizable) transactions across regions using consensus and carefully bounded clocks.
Defaults to eventually consistent reads; a strongly consistent read option reads from the leader at higher cost.
The social graph cache is eventually consistent but provides read-after-write for a user's own actions within a region.
Google Docs-style editing relies on operational transforms or CRDTs so concurrent edits converge without coordination.
In an interview
- Don't say "strongly consistent" or "eventually consistent" for the whole system; pick a model per kind of data and justify it.
- Call out read-your-writes whenever you add read replicas or caches, and say how you'll provide it.
- Use R + W > N when discussing quorum replication.
- For concurrent writes, say how conflicts are resolved: last-write-wins, version vectors, or CRDTs.