Skip to main content

Design a Collaborative Editor (Google Docs)

Level 10: Level 10: Applied Case Studieshard40 mincollaborative-editorcrdtot

Converge concurrent edits with OT (server-ordered, transform indices, memory-lean, Docs-style) or CRDTs (per-character ids, commutative merge, offline/P2P-friendly), broadcast ephemeral presence over WebSocket, persist an op log plus snapshots for replay and reconnect, and route all editors of a document to one server for coherent ordering.

The whole problem is convergence

The whole problem of a collaborative editor is convergence: many people edit the same document concurrently, each edit is applied against a slightly different local state, and yet every replica must end up byte-for-byte identical, while preserving what each user intended. Last-write-wins on the whole document is the disqualifying answer: if Alice and Bob both type at the same moment, LWW throws one person's work away. There are two correct families: Operational Transformation (OT) and CRDTs.

Operational Transformation

Edits are operations like insert(pos=5, "x") and delete(pos=8). When two operations are made concurrently against the same base, applying them in different orders gives different results, so OT transforms an incoming operation against operations that were applied before it locally, adjusting indices so intent is preserved. If Alice inserts at position 5 and Bob concurrently inserts at position 3, Bob's op shifts Alice's effective position to 6. OT is what Google Docs uses. It is proven and compact, but the transformation functions are notoriously subtle, and classic OT relies on a central server to impose a single canonical order of operations.

CRDTs

Instead of transforming operations, CRDTs give every character a globally unique, totally-ordered identifier (often a fractional index or a dense position between two neighbors) so that concurrent inserts have a deterministic, commutative merge order with no transformation needed. Sequence CRDTs (RGA, Logoot, YATA as used by Yjs, Automerge) let replicas merge in any order and converge. The advantage is they work peer-to-peer and offline without a central sequencer; the cost is metadata overhead (every character carries an id, and deleted characters may linger as tombstones).

OT:   op flows to server -> server orders + transforms against concurrent ops -> broadcasts transformed op
CRDT: each char has a unique id -> ops commute -> any replica merges in any order -> same result

The tradeoff: OT is server-centric, memory-lean, battle-tested, but the transform logic is fragile and hard to extend to rich data. CRDTs are decentralization-friendly and offline-first, conceptually cleaner to reason about for convergence, but carry more per-character metadata and need periodic tombstone garbage collection. For a server-backed product like Docs, OT (or a server-ordered CRDT) is pragmatic; for offline-first or P2P (local-first apps, Figma-like tools), CRDTs shine.

Transport, persistence, scaling

Edits flow over a persistent WebSocket to a per-document collaboration server. Beyond the edits themselves, you broadcast presence: each user's cursor position and selection, and who is online. Presence is high-frequency but ephemeral and lossy-tolerant, so you send it on a lighter channel and never persist it.

You do not save the document as a blob on every keystroke. You append operations to an op log and periodically write a snapshot so a new joiner can load the latest snapshot plus the tail of ops rather than replaying from creation. Undo/redo and history come from the op log. On reconnect after being offline, the client sends its queued local ops and receives the ops it missed (identified by a version/sequence number), then transforms or merges to catch up.

All editors of one document must reach the same collaboration server (or a consistent group) so ordering is coherent, so you route by document id to a specific server/shard (sticky, consistent-hashed). Different documents scale out horizontally.

Interview nuance: the killer follow-up is offline editing. If a laptop edits offline for an hour and reconnects, you cannot LWW. You must replay/merge the queued ops against everything that happened meanwhile. CRDTs make this natural (merge is commutative); OT requires transforming the whole queued batch against the missed history.

Recap: converge concurrent edits with OT (server-ordered, transform indices, memory-lean, Docs-style) or CRDTs (per-character ids, commutative merge, offline/P2P-friendly), broadcast ephemeral presence over WebSocket, persist an op log plus snapshots for replay and reconnect, and route all editors of a document to one server for coherent ordering.

Apply

Your turn

The task this lesson builds to.

Design a document that multiple users edit simultaneously with all edits converging and cursors shown live.

Think about

  1. What is the OT vs CRDT tradeoff for convergence and intention preservation?
  2. How do you broadcast presence and cursors in real time?
  3. How do you persist and replay edits and handle offline reconnection?

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Design the collaboration engine for Figma, where the shared document is not text but a tree of graphical objects (frames, shapes, layers with properties), edited by dozens of designers in real time. Explain why Figma chose a CRDT-style model and how editing a property tree differs from editing a text string.

Think about

  1. Why does a tree of typed-property objects favor CRDT registers over text OT?
  2. How do LWW-registers per property and ordered-list CRDTs converge?
  3. Why is losing one concurrent property edit acceptable for design tooling?