Eventual consistency is a consistency model for distributed data: after a write stops, all replicas converge to the same value, but they may return stale data in the window before they catch up. It trades immediate, global agreement for availability and partition tolerance.
Why it matters
A single database with one writer can offer strong consistency: every read sees the most recent write. The moment data spans replicas, regions, caches, or services, holding that guarantee requires coordination that blocks on the network and fails when a partition occurs. Eventual consistency accepts brief divergence so the system stays available and responsive, which is the right trade for most high-scale, geographically distributed, or asynchronous workloads.
Strong vs eventual
| Strong consistency | Eventual consistency | |
|---|---|---|
| Read after write | Always current | May be stale briefly |
| Coordination | Synchronous, blocks | Asynchronous, converges |
| Availability under partition | Reduced | Preserved |
| Typical use | Single-node ACID, leader reads | Replicas, caches, event-driven flows |
How it shows up
Eventual consistency is the default whenever state propagates asynchronously:
- Replicated stores, a read replica lags the primary by milliseconds to seconds.
- Event-driven systems, a consumer updates its own view after an event arrives, so event-driven architecture is eventually consistent by construction.
- Sagas, the saga pattern replaces a cross-service transaction with local commits plus compensations, so the overall process is consistent only once every step settles.
- Caches and search indexes, a denormalized read model trails the source of truth until the next refresh.
sequenceDiagram participant Client participant Primary participant Replica Client->>Primary: write x = 2 Primary-->>Client: ack Client->>Replica: read x Replica-->>Client: 1 (stale) Primary->>Replica: replicate x = 2 Client->>Replica: read x Replica-->>Client: 2 (converged)
Designing for it
Because clients can observe intermediate states, the application has to tolerate them:
- Idempotent writes, retries and reordering are normal, so make handlers idempotent and expect at-least-once delivery.
- Conflict resolution, decide how to merge concurrent updates: last-writer-wins, version vectors, or CRDTs for automatic convergence.
- Read-your-writes, when a user must see their own change immediately, route their reads to the primary or pin them to an up-to-date replica.
- Surface state honestly, show “pending” or “processing” rather than implying a change is globally durable before it is.
Trade-offs
- Clients may read stale data, so workflows that demand a fresh read need explicit handling.
- Reasoning about correctness is harder: bugs hide in the convergence window and only appear under concurrency or failure.
- Some operations genuinely need strong consistency (account balances at the point of debit, unique-constraint enforcement); do not force eventual consistency where invariants must hold immediately.
