How CRDTs work
Two people edit a list on two offline phones. When they reconnect, they get one list, with no conflict dialog and no lost edits.
Local-first apps, like Linear's sync engine, have to merge copies that drifted apart. Usually a server decides, or the user does. A Conflict-free Replicated Data Type (CRDT) designs the data so merging is automatic and always gives the same result, in any order, even if you merge twice.
An Observed-Remove Set, live
Replica A · phone 1
Replica B · phone 2
bread on A, add it again on B, then sync.
Bread stays: a concurrent add beats a remove. "Show the plumbing" reveals the tags.
Merging by rules
An OR-Set never has to pick whose edit wins. Every add gets a hidden unique
tag, like bread#a3. A remove marks only the tags it has
observed. An item is present while any of its tags is unremoved. To merge,
take the union of all adds and all removes. Order doesn't matter, and merging twice changes
nothing.
Why adds win
A's remove marked the tag it could see, bread#a1. B's re-add made a
new tag, bread#b7, that A never saw. So bread stays. It's
also the safer default: a deleted item takes one tap to restore, and data a merge threw away
is gone.
What makes it work
CRDT merges are commutative, associative and idempotent, so messages can arrive out of order, in batches or twice. Replicas that saw the same edits always end up the same, with no coordination. That guarantee is strong eventual consistency. Counters, maps, JSON and text all have CRDT designs. Yjs and Automerge are the libraries to use.
About the toy. It keeps every tag forever. Production CRDTs clean up old tags and compress, and text CRDTs do extra work to keep characters in order. Unique tags and merge-by-union work the same way.