Home / Software y Cloud / CRDT: the discrete math that keeps two edits from fighting

CRDT: the discrete math that keeps two edits from fighting

Two people type into the same paragraph at the same time, each from a different city, and neither loses what they wrote. Behind that everyday scene lies a fairly serious computer science problem: how to make several replicas that cannot talk to each other in real time end up showing exactly the same document.

The modern answer is called CRDT (Conflict-free Replicated Data Type). It does not remove conflicts by magic: it designs them away, so that the conflict stops existing as a problem.

The problem of order

Inside a single machine, two simultaneous writes are settled by a total order: clocks, locks and the memory bus impose which one goes first. In a distributed system that order does not exist. There is only a partial order: if A and B never communicate, nobody can claim A happened before B. Leslie Lamport’s happened-before relation formalises precisely that, and vector clocks materialise it as a vector of counters, one per replica: if A’s counter has not reached B’s and vice versa, both operations are concurrent.

When two concurrent operations touch the same piece of data there are three possible ways out: ask a central authority to arbitrate, transform one operation so it becomes equivalent when applied in another order, or make the result identical regardless of order. The second is OT (operational transformation), the technique Google Docs relied on for years: it needs a server to serialise and transform operations, and every client needs to know the exact history. The third is CRDT.

A semilattice in disguise

A state-based CRDT is defined by a merge operation with three properties: it is commutative (order does not matter), associative (grouping does not matter) and idempotent (applying the same thing twice changes nothing). Those three letters, ACI, define a semilattice with a least element. If merge has those properties and every replica eventually sees every state, convergence is guaranteed by algebra rather than by luck.

The minimal example is the G-Counter: a counter that only goes up. Each replica keeps a vector with its own slot, and merging means taking the maximum position by position. Nobody coordinates anything; the final sum is the same everywhere. The PN-Counter adds a second, decreasing vector to allow subtraction, and the LWW-Register (last-write-wins) settles writes to a scalar value by storing a pair (logical timestamp, replica identifier) and breaking ties with the ID, deterministically.

Text: the hard case

Text is not a counter: every insertion shifts the positions of everything after it. Sequence CRDTs solve this by giving every character an immutable positional identifier instead of an index. Inserting between two characters means picking an identifier that falls between its two neighbours under a dense order; in RGA, YATA or Logoot that is done by comparing tuples of (counter, replica) and applying a tie-break rule for concurrent insertions into the same gap. Deletions do not remove the character: they mark it as a tombstone, because if it disappeared, an old operation arriving late would insert content back in the wrong position.

Hence the real cost of the technique: metadata. Every character drags its identifier along, every deletion leaves a tombstone, and every replica keeps enough history to resolve operations that have not arrived yet. In long, heavily edited documents that history has to be pruned, and doing so without breaking convergence is the hard part of shipping this, not the theory.

State versus operations

Operation-based CRDTs (CmRDT) propagate just the operation — “insert X after Y” — and require the delivery channel to guarantee causality and no duplicates: if an operation is applied twice or before its predecessor, convergence breaks. State-based ones (CvRDT) ship the whole replica and rely on the ACI merge, which is far more tolerant of chaotic networks but heavier on bandwidth. The middle ground is the delta-state CRDT: send only the delta of the state since the last sync, while keeping the algebraic guarantees.

That trade-off explains why the industry has converged on specific implementations: Yjs and Automerge in collaborative editors and offline-first apps, native CRDTs in databases such as Riak and the counters in Cassandra or Redis, and observable maps in managed services. In all of them, when the user gets connectivity back there is no reconciliation dialogue: the merge simply happens.

The underlying lesson is simple and powerful: if you can express your problem as a structure whose merge is commutative, associative and idempotent, coordination stops being necessary. It is not that CRDTs resolve conflicts; it is that they choose structures in which conflicts never arise in the first place.