pickuma.
Dev Knowledge

What a CRDT Is, and How Collaborative Apps Stay in Sync

A practical explainer on conflict-free replicated data types: the merge math behind them, the main CRDT families, and how libraries like Yjs and Automerge use them.

8 min read

Open the same document in two browser tabs, go offline in both, type a different sentence in each, then reconnect. A good collaborative editor will show you both sentences, in a stable order, on every device — no “resolve conflict” dialog, no lost keystrokes. The data structure that makes that possible is usually a CRDT.

CRDT stands for Conflict-free Replicated Data Type. The name is a mouthful, but the idea it encodes is narrow and precise: a data type whose replicas can be edited independently and then merged automatically, with a mathematical guarantee that every replica ends up identical once they have all seen the same set of changes. No central referee decides who wins. The merge rule itself does the deciding, and it does so the same way no matter what order the changes arrive in.

The merge math that makes “conflict-free” true

The word “conflict-free” is doing real work. It does not mean two people can never touch the same character. It means the merge function is designed so there is always a defined, deterministic answer, and that answer does not depend on timing or network order.

Concretely, a state-based CRDT (the literature calls these CvRDTs, for convergent) defines a merge operation over its values, and that operation has to satisfy three properties:

  • Commutative: merge(a, b) == merge(b, a). Order of arrival does not matter.
  • Associative: merge(merge(a, b), c) == merge(a, merge(b, c)). Grouping does not matter.
  • Idempotent: merge(a, a) == a. Receiving the same update twice changes nothing.

If merge has all three, the set of possible states forms a structure called a join-semilattice, and replicas are guaranteed to converge. That guarantee is the whole point. You can drop packets, deliver them out of order, deliver them twice, or sync three devices in a triangle — and as long as every change eventually reaches every replica, they all land on the same value.

There is a second flavor, operation-based CRDTs (CmRDTs, for commutative). Instead of shipping whole states and merging them, replicas broadcast individual operations, and the operations are designed to commute. This is lighter on bandwidth but assumes the network delivers every operation exactly once. Most production libraries blur the line and use an optimized hybrid, but the convergence requirement is the same.

The CRDT zoo: counters, sets, registers, and text

CRDTs come as a toolkit of building blocks, each solving one shape of data.

Counters. A G-Counter (grow-only) gives each replica its own slot and only ever increments its own. The counter’s value is the sum of all slots; merge takes the max of each slot. A PN-Counter pairs two G-Counters, one for increments and one for decrements, so you can support subtraction without breaking convergence.

Registers. A single value that gets overwritten. The common version is a Last-Write-Wins register, which attaches a timestamp (usually a logical clock, not a wall clock) to each write and keeps the highest. LWW is simple and is exactly where the “convergence is not intent” warning bites: concurrent writes mean one silently loses.

Sets. A G-Set only allows adds. An OR-Set (observed-remove) lets you add and remove the same element repeatedly by tagging each add with a unique id, so a remove only cancels the specific adds it has seen. This is how you avoid the classic bug where one replica’s “remove” accidentally erases another replica’s later “add.”

Sequences. This is the hard one, and it is what powers collaborative text. A sequence CRDT assigns each character a position identifier that sorts stably between its neighbors, so two people inserting at “the same spot” get distinct, orderable positions instead of clobbering each other. Algorithms here have names like RGA, Logoot, and YATA. YATA is the model behind Yjs; Automerge uses a related approach.

Notion

A widely used collaborative workspace where multiple editors can work on the same page in real time — the kind of multiplayer editing experience CRDT-style sync is built to support.

Free tier; paid plans from $10/user/mo

Try Notion

Affiliate link · We earn a commission at no cost to you.

How a real collaborative app uses one

Put the pieces together and a multiplayer editor looks like this. Each client holds a full replica of the document as a CRDT. When you type, the client applies the change locally and immediately — that is why good collaborative apps feel instant even on a bad connection. The change is also encoded as a compact update and sent to other clients, usually relayed through a lightweight server or a peer mesh.

The server in this model often does almost no merging logic of its own. With a library like Yjs, the server can be a dumb relay plus a persistence layer: it forwards binary updates and stores them so a client joining late can catch up. The convergence guarantee lives in the CRDT, not the server, which is what lets these systems keep working offline and resync cleanly later.

The main alternative you will hear about is Operational Transformation (OT), the older approach behind Google Docs. OT transforms each operation against concurrent ones to preserve intent, but it traditionally needs a central server to order operations, which makes true peer-to-peer and offline-first harder. CRDTs trade some metadata overhead for not needing that central authority. Neither is strictly better; they sit at different points on the same tradeoff curve.

FAQ

Do I need to implement a CRDT myself?+
Almost never. Getting the merge math and sequence positioning right is genuinely hard, and the edge cases (tombstones, concurrent inserts at the same index, garbage collection) are where subtle bugs live. Reach for a maintained library like Yjs or Automerge instead of writing your own.
Are CRDTs only for text editors?+
No. The counter, set, and register types are useful for any replicated state: presence indicators, shared shopping carts, collaborative whiteboards, distributed configuration. Text editing is just the most demanding case because it needs a sequence CRDT.
What happens with a true conflict, like two people editing the same value?+
The CRDT resolves it deterministically — for a last-write-wins register, the higher logical timestamp wins and the other write is dropped. The replicas will agree, but one user's change is gone. If silently losing data is unacceptable, you need application-level handling, such as storing both values and prompting a human.

The one-sentence version to keep: a CRDT is a data type whose merge rule is commutative, associative, and idempotent, which mathematically forces every replica to converge no matter how the network behaves. Everything else — the counters, the sets, the sequence algorithms — is engineering around that single guarantee.

Related reading

See all Dev Knowledge articles →

Get the best tools, weekly

One email every Friday. No spam, unsubscribe anytime.