Skip to content

CONCEPT Cited by 1 source

Read-your-writes consistency

Definition

Read-your-writes consistency (RYW) is the session-consistency guarantee that, within a single client session, any read issued after a successful write observes a state that includes that write (or a later one). It is a strictly weaker property than strong consistency — other sessions may still see stale state — but strictly stronger than raw eventual consistency, which permits a session to fail to see its own writes.

Formally, for a session S with writes w1, w2, … committed at times t_w1, t_w2, … and a read r issued at time t_r:

RYW(S):  t_r > t_w_i  ⇒  r observes w_i's effect  (for every w_i of S)

The guarantee is scoped to session S: a different session may observe a pre-w_i state at the same wall-clock time and that does not violate RYW.

Why it matters

RYW is the consistency floor a human user "feels". A user clicks "Save", the request succeeds, the page reloads — and the user's own edit is gone. This is the single most common way users perceive a database as "broken", even if the system is technically eventually consistent and the edit will show up in ~100 ms. It is the UX contract of basically every interactive application:

"This tells Rails to send all reads to our read-only region and writes to our primary. After each write, it will set a cookie that will send all reads to the primary for 2 seconds, allowing users to read their own writes." (Source: sources/2026-04-21-planetscale-introducing-planetscale-portals-read-only-regions.)

The PlanetScale Portals launch post is canonical because it names the problem explicitly ("This protects our users from ever reading stale data due to replication lag") and provides the canonical mechanism — a session cookie pinning reads to primary for a bounded window.

How RYW breaks

RYW is trivially preserved in a single-primary / read-from-primary architecture: every read goes to the same server that committed the write, so the write is visible by construction.

RYW breaks the moment a system introduces read-write splitting — writes to primary, reads to replica pool. A write commits on primary at time t_w. The write propagates to replica R at time t_w + lag(R). A read issued to R in the window [t_w, t_w + lag(R)) returns pre-write state. This window is replication-lag-sized — typically sub-second on a healthy cluster, but unbounded during replication stalls.

RYW breaks harder with regional read replicas: cross-region lag is larger (cross-ocean is ~100 ms minimum just from physics, often 500 ms–several seconds under load), and the blast radius of a stalled replica is an entire region's read traffic returning ghost-reads.

Four mechanisms to preserve RYW

1. Read from primary always. Trivially correct; throws away the entire point of having replicas. Used for write-your-writes-critical flows by exception (e.g. a form submission's post-save redirect).

2. Sticky session → sticky replica, plus lag < sticky-window. Pin a user's reads to a specific replica. If the replica is caught up at time t_w (synchronously replicated primary → replica), RYW holds. Brittle — requires a session-layer routing primitive and a tight bound on replica lag.

3. Session token / LSN / GTID comparison. Server returns an opaque position token on write; the client includes the token on subsequent reads; a read that cannot be satisfied at that token is either delayed or forwarded to primary. Correct, precise, but requires token plumbing through every request path. Approximates what MongoDB's $clusterTime and PostgreSQL's logical sequence numbers offer natively.

4. Time-bounded primary-read window after write. On commit, set a flag (cookie, session variable, in-memory TTL) that forces the user's subsequent reads to primary for Δ seconds. Correct iff Δ > max(lag(R)) over the replica pool — the classic session-cookie pattern from the Portals post. Cheap, coarse, works with any ORM that supports role switching (Rails DatabaseSelector, Django router, Laravel DB::connection('read'), etc.).

Failure modes

  • Δ too small for p99 replication lag. User occasionally sees ghost-reads. Debugging signal: users complain "my edit disappeared and then came back 3 s later". The 2 s default in the Portals post is reasonable for a healthy cluster but insufficient during replication stalls.
  • Cookie not set / not propagated. Some auth flows, agent traffic, or server-to-server calls may not carry the session cookie, so they always read from replica regardless of recent-write status. Typically fine for agents (they don't care about RYW for their own writes) but a source of subtle bugs.
  • Write failure + optimistic cookie. If the app sets the cookie before knowing whether the write committed, a write that rolled back still pins the user to primary for Δ seconds. Harmless in that direction — the user reads fresher data than necessary, not staler.
Model Within session Across sessions
Strong consistency
Monotonic reads reads never go backwards in time
Read-your-writes ✓ (your own writes)
Monotonic writes own writes applied in order n/a
Eventual consistency

RYW is one of four session guarantees (Terry et al., 1994); any RYW-enforcing mechanism also typically gives monotonic reads as a side effect if it uses a monotonic position token (#3 above) or pins to a single replica (#2 above).

Seen in

Last updated · 378 distilled / 1,213 read