Read-your-writes: why users see old data after saving, and four ways to fix it
Replication lag makes users see their own changes vanish. What read-your-writes means, four ways to provide it, and what each one costs.
4 min read
When a database copies writes to replicas asynchronously, a user who saves a change and then reads from a replica can see the old value, as if the save never happened. Read-your-writes consistency is the promise that a user always sees their own writes. You can provide it by reading from the primary for a short window after a write, by always reading the user’s own data from the primary, by passing a version the replica must catch up to, or by using overlapping read and write quorums. Each one moves load or latency somewhere else.
What goes wrong
A typical setup sends writes to one primary and spreads reads across replicas, which receive the writes a little later. That delay, the replication lag, is usually milliseconds and occasionally seconds or minutes: during a large batch job, a replica restart, or a network problem.
Now a user edits their display name, the page reloads, and the reload is served by a replica that is two seconds behind. The old name appears. The user edits it again. To them, the product is broken, even though every component did what it was designed to do.
Two related guarantees are worth knowing by name:
- Read-your-writes: a user sees their own writes. Other users may still see older data.
- Monotonic reads: a user never sees data go backwards, for example a comment that appears and then disappears because two reads hit replicas with different lag.
Fix 1: read from the primary after a write
After a user writes, send that user’s reads to the primary for a short window, for example the replica lag you measure at p99.9 plus a margin.
Costs: extra load on the primary, which is the part you added replicas to protect. The window is a guess: if lag exceeds it, the bug comes back. It works well when writes are rare compared with reads, such as profile edits.
Fix 2: read the user’s own data from the primary
Some data is only ever edited by its owner: their profile, their settings, their drafts. Serve those reads from the primary for the owner, always, and from replicas for everyone else.
Costs: the primary carries every owner’s reads of their own data, which is fine for settings pages and too much for a busy feed. Do not confuse this with pinning a user to one replica (session stickiness): that keeps their reads from going backwards (monotonic reads), but a pinned replica that is behind still hides the user’s own write.
Fix 3: carry a version and wait for it
When the write commits, return its position in the replication log (a log sequence number, a transaction id, or a timestamp). The client sends it with the next read, and the replica serving the read waits until it has applied at least that position, or the read goes to the primary.
Costs: more moving parts: the token has to travel through every layer, including caches and background jobs. A replica far behind makes the read slow or forces a fallback. In exchange, it is precise: no guessed windows, and the primary only takes reads when a replica truly is behind.
Fix 4: overlapping quorums
In leaderless systems with N copies, a write waits for W copies to acknowledge and a read asks R copies and takes the newest value. If R + W > N, every read set overlaps every write set in at least one copy, so the read can see the latest acknowledged write. With N = 3, W = 2 and R = 2 is the common choice.
Costs: every read and every write waits for the slower of several copies, so the tail latency of the cluster sets your latency. When too many copies are down, operations fail instead of returning old data. And overlap alone is not a full guarantee: concurrent writes, failed writes that reached some copies, and “sloppy” quorums that write to stand-in nodes can still return surprising results. Check what your database actually promises.
Choosing
| Approach | Best when | Main cost |
|---|---|---|
| Primary after a write | Writes are rare, lag is short | Primary load; the window is a guess |
| Owner reads from primary | Data only its owner edits | Primary load grows with owners’ reads |
| Version token | You need precision at scale | Complexity across every layer |
| Overlapping quorums | Leaderless database | Latency of several copies; availability during failures |
Whichever you pick, measure replication lag as a first-class metric with an alert, because every one of these designs assumes you know how far behind your replicas are.
Common questions
What is read-your-writes consistency?
A guarantee that after a user writes data, that same user’s later reads return the write or something newer. It says nothing about what other users see.
Is eventual consistency the same as read-your-writes?
No. Eventual consistency only promises that copies converge if writes stop. A user can still read an old value right after their own write. Read-your-writes is a stronger guarantee for the writer.
Does R + W > N guarantee strong consistency?
It guarantees that read and write sets overlap, which lets a read see the latest acknowledged write in the normal case. It does not by itself handle concurrent writes, partially failed writes or sloppy quorums, so it is not the same as linearizability.
How long should the “read from primary” window be?
Base it on measured replication lag at a high percentile plus a margin, and alert when lag exceeds it. If lag regularly exceeds any window you can afford, use a version token instead.