Architecture

CRDT vs OT: how collaborative editors merge edits

Google Docs transforms operations. Yjs-based editors converge data structures. The choice barely shows in a demo and shows up all over your architecture - plus a five-step test for verifying any vendor's claim.

9 min read

Two people type in the same paragraph at the same time. Their keystrokes cross in flight. Both editors have to end up showing exactly the same text — and neither user should see their work vanish.

There are two established ways to solve that, and the major editors have split between them. The choice is mostly invisible in a demo and quite visible in your architecture diagram, so it is worth understanding before you pick a vendor.

Operational Transformation

OT is the older approach, and the one behind Google Docs. Edits are expressed as operations — insert "x" at position 4, delete 2 characters at position 9— and when two operations are made concurrently, the system transforms one against the other so the positions still make sense after the other edit landed.

If I insert at position 4 and you delete at position 2 at the same moment, my insert has to become “at position 3” before it can be applied on your copy. That transformation function is the whole game, and it has to be correct for every pair of operation types.

CKEditor 5 is the notable rich text implementation in this camp: they extended OT to tree-structured data and describe it as the product of several years of dedicated research and development. That is a fair signal of how much work the approach demands.

CRDTs

A Conflict-free Replicated Data Type takes the opposite route: instead of transforming operations to fit, design the data structure so that concurrent changes always merge to the same result, in any order.

Each character gets a globally unique identity rather than a positional index. “Insert after the character with id A7” means the same thing on every replica regardless of what else happened, so there is no position to fix up.

Yjs is the dominant rich text CRDT in practice. Tiptap, Froala and RichTextEditor all build on it; Lexical ships an official Yjs binding.

What actually changes for you

QuestionOTCRDT
Server roleUsually authoritative — orders and transforms operationsCan be a dumb relay that forwards updates
Offline editingHarder — divergence must be reconciled on reconnectNatural — merge on reconnect is the normal case
Document overheadLowHigher (identities and tombstones)
Self-hosting difficultyHigher — the server contains real algorithmLower — standard relays are off-the-shelf
EcosystemMostly vendor-specific implementationsShared: Yjs providers, awareness, persistence

The practical consequence for most buyers is the server. With OT you are usually adopting the vendor’s collaboration backend — hosted, or self-hosted on their terms and often their higher tiers. With CRDTs the sync layer is commodity: a Yjs WebSocket relay is a small, replaceable process you can run yourself.

Do not take convergence on faith — test it

Both approaches are sound in theory. What breaks in practice is the binding between the algorithm and the editor’s DOM, and that failure mode is nasty because everything looksfine: the server accepts connections, presence works, cursors move — and text silently does not merge, or the editor quietly drops to a degraded “last write wins” mode.

We have hit exactly that ourselves. A bundling mistake meant the CRDT engine and the host application each loaded their own copy of Yjs; every protocol-level test passed while real text sync was completely broken, because the two copies did not recognise each other’s types.

The lesson is a test procedure. When evaluating any collaborative editor, insist on all five:

  1. Two real editors, one real server. Not a protocol test, not two documents in one page without a server. Actual editor instances syncing over the wire.
  2. Confirm the sync mode. Ask the editor what mode it is in and assert it is the real one. Many implementations fall back silently; if there is a status API, check it says CRDT (or OT) and that the fallback reason is empty.
  3. Both directions. A → B and B → A. One-way sync is a surprisingly common bug.
  4. Interleaved edits into the same paragraph. Alternate typing between the peers with realistic gaps, then assert both documents are byte-identical and every edit survived.
  5. Disconnect and reconnect. Edit on both sides while one is offline, reconnect, and check convergence. This is where the theory earns its keep.

Choosing

Neither approach is universally better, and for most teams the algorithm is not the deciding factor — the operational shape is.

RichTextEditor takes the second path: a per-node Yjs CRDT engine with a self-hosted relay, included in the licence rather than sold as a collaboration add-on. The architecture is documented in the CRDT internals guide, and there is a two-editor demo if you would rather try the test procedure above than read about it.


RichTextEditor is a perpetual-licence JavaScript editor — one purchase, self-hosted, no metered editor loads. Download the evaluation or see how it compares.