Tech
Tech · ◉ Evergreen

Everyone edits. Nobody waits. It still agrees.

by · ·5 min·Working Theory

CRDTs in plain English. How two people can edit the same thing offline, on opposite sides of the planet, with no central referee — and still end up with the exact same result. The trick, the families, and the honest price you pay for skipping the coordinator.

Two people open the same shared note. Both go offline — one on a plane, one in a basement. Both edit. Both come back online an hour later. What should the note say?

If you’ve read the earlier pieces in this corner, you know two of the honest answers. Consensus (the “they all have to agree” piece) says: make everyone agree on one order of events before anyone proceeds — safe, but it needs a quorum and a round trip, which the person on the plane can’t make. Vector clocks (last week’s piece) say: at least you can detect that the two edits were concurrent, so you don’t silently clobber one with the other — but detecting a conflict isn’t resolving it; someone still has to decide.

CRDTs are the third answer, and it’s a sneaky one: structure the data so that there’s no conflict to resolve in the first place. CRDT stands for Conflict-free Replicated Data Type, and the whole idea is to design the data and its merge rule so that any two replicas which have seen the same set of updates compute the same final state — no matter what order the updates arrived in, no matter if some arrived twice, and with nobody in charge.

The magic is just three boring algebraic properties, hiding under a fancy name. Make the merge commutative (A-then-B equals B-then-A), associative (grouping doesn’t matter), and idempotent (applying the same update twice changes nothing). Get all three, and order stops mattering. Duplicates stop mattering. Timing stops mattering. Every replica, once it’s seen everything, lands in the same place on its own.

Node A (offline) a:3 b:1 counts its own bumps in a Node B (offline) a:1 b:4 counts its own bumps in b merge = slot-wise max both nodes, after merge a:3 b:4 value = 7 max(3,1)=3, max(1,4)=4 — same answer on both, any order, even if a message arrives twice
A grow-only counter: each node owns one slot, merge takes the bigger number in each slot, the value is the sum. Commutative, associative, idempotent — so order and duplicates can't change the result. Original diagram · Working Theory

The counter above is the gentlest example. Want a set instead of a counter? Union is already commutative/associative/idempotent, so a grow-only set is a CRDT for free; an observed-remove set adds little unique tags so that a concurrent add-and-remove has a defined outcome instead of a coin flip. Want text? That’s what powers live collaborative editors — sequence CRDTs (the family behind libraries like Yjs and Automerge) give every character a position that two people can insert around without stepping on each other. There are two broad styles under the hood: state-based, where nodes ship their whole state and merge with a join rule, and operation-based, where nodes ship individual operations that are built to commute. Same promise either way: converge without a coordinator.

Now the honest price, because this corner doesn’t sell free lunches.

You pay in metadata. That “defined outcome” for a remove usually means leaving a tombstone behind; those unique tags and causal markers accumulate, and now you need garbage collection and compaction to keep them from growing forever. (If that smells like the tombstones in the LSM-tree piece, it’s the same tax in a different coat.)

Convergence is not the same as being right. A CRDT guarantees every replica agrees on a state. It does not guarantee it’s the state a human wanted. If two people concurrently set the title to “Q3 Plan” and “Q3 Roadmap,” a last-writer-wins register will converge — to one of them, deterministically — and the other person’s edit simply vanishes, with no conflict surfaced, because the type “resolved” it for you. Vector clocks would have at least told you those two were concurrent. A CRDT quietly absorbs it. Sometimes that silence is exactly what you want; sometimes it’s a lost edit nobody noticed.

Not everything is a CRDT. Anything that needs an invariant across items — “this balance can never go negative,” “there is exactly one workspace admin” — cannot be maintained by independent replicas merging on their own. Two replicas can each be locally fine and jointly break the rule. That’s the one job CRDTs can’t do, and it’s precisely the job consensus exists for.

So the build decision is a clean fit test. Reach for a CRDT when you’re offline-first or collaborative or active-active across regions, when availability beats waiting on a quorum, and when “converge to some deterministic state” is an acceptable answer. Reach for consensus when you need a single agreed order or a hard global invariant. And remember the supporting cast: gossip (the “rumor beats a memo” piece) is a great transport for spreading CRDT updates around, and vector clocks are the tool that detects the very concurrency a CRDT is designed to absorb. They’re siblings, not rivals.

Sources

  • Shapiro, Preguiça, Baquero & Zawirski 2011 (Conflict-free Replicated Data Types)
  • G-Counter, PN-Counter, G-Set, OR-Set, LWW-Register
  • sequence CRDTs (RGA, Logoot, Yjs, Automerge)
  • CRDTs in production in Redis, Riak, and Azure Cosmos DB

Liked this? Get the next one in Working Theory.

Going weekly in August (it's in beta now). One genuinely interesting read on building, the brain, and the science most people missed.

Subscribe →
Got a reaction, a counter-example, or something I missed? Reply by email — I read everything.
◉ join in

Where have you hit this — in a product you use, or one you're building?

Threads open here soon. For now, the conversation lives two clicks away — discuss on GitHub, or just reply by email. I read and answer everything.