InterviewKata
System design · Worked design D19 of 46 · Data and infrastructure · Long form

Design a collaborative editor

Two people type into the same paragraph at the same moment, each on their own copy, with a network in between. Within a second both screens must show the same text, and it must be the text both of them meant. This design is about the algorithms that merge concurrent edits (operational transformation and CRDTs) and the system around them: real-time connections, an operation log, snapshots and presence. It follows the interview framework phase by phase.

1. The prompt

"Design Google Docs: many users edit the same document at once and see each other's changes and cursors live; documents keep a full version history."

Most designs in this track scale out by spreading load. This one does the opposite for each document: it funnels every edit through one place so there is a single order. The interesting part is what happens between two copies that disagree.

2. Frame the problem

How many editors per document?

Usually 1–10; rarely up to 100.

Per-document load is small; one server per document works.

How many documents and open sessions?

100M documents; ~5M editors connected at once.

The connection tier is the big fleet, not the documents.

Must it work offline?

Short disconnections, yes; long offline editing is a stretch goal.

Pushes towards OT with a central server, with CRDTs as the offline option.

Plain or rich text?

Rich text, but discuss plain text first.

The merge algorithm is clearest on characters.

Version history?

Yes, back to the start.

An append-only operation log plus snapshots.

Do cursors need saving?

No, only live.

Presence stays in memory, throttled.

3. What it must do

  1. Open a document and edit it; see other people's edits and cursors in real time.
  2. Merge concurrent edits automatically; nobody's typing is lost.
  3. Keep version history; share with view, comment or edit permissions.

Not now:

4. How well it must do it

TargetWhy this number
Instant local typing; others see it within a few hundred ms speedWaiting for a server round trip per keystroke feels broken.
Convergence: every copy ends up identical and preserves each person's intent consistencyDiverged copies are silent data loss.
Durable: an acknowledged edit is never lost durabilityPeople trust the editor with their work.
Scale: millions of open sessions load shapeLots of connections, each fairly quiet.

5. Numbers that change the design

QuantityWorking→ so we…
Open connectionsSay 5M concurrent editors5M WebSockets → so a gateway tier holding ~50–100K connections a machine
OperationsA typist makes ~5 edits a second while active; say 20% typing at once~5M ops a second in total, but each document sees only a handful → so route each document to one server
Op logEach op ~100 bytesHundreds of TB a year of ops → so snapshot and compact; keep recent ops hot
PresenceCursor moves can be 20+ a second per user→ so throttle to a few a second and never store them

6. The nouns

documents  doc_id, owner_id, acl, current_rev, latest_snapshot_rev
ops        (doc_id, rev) → author_id, op: insert "s" at 3 | delete 2 at 7, base_rev, created_at   (append-only)
snapshots  (doc_id, rev) → blob key of the full content
presence   doc_id → user_id → cursor, selection                (memory, never stored)

7. The contract

GET /v1/docs/{id}                → {snapshot, revision, ops since snapshot}
WS  /v1/docs/{id}/session
  client → {op: insert "s" at 3, base_rev: 41}
  server → {ack: 42}                         (to the author)
  server → {op: insert "s" at 5, rev: 42}    (to everyone else, transformed)
  both   ↔ {cursor: 17}                      (presence, not saved)

Data flow: (1) open: load a snapshot and the ops after it → (2) type: apply locally at once, send the op with its base revision → (3) the document server transforms it against ops the client hadn't seen, assigns the next revision, appends it to the log → (4) ack the author, broadcast to everyone else → (5) snapshot every N ops.

8. First working version

WebSockets to a server that saves the document and relays edits as positions.

8.1 Two people type at once

Each edit is applied locally and sent as "insert at position". When edits don't overlap in time this works; when they do, the copies diverge.

8.2 Opening a document

Load the latest saved text.

Parked for later (section 9 fixes each)

  1. Concurrent edits shift positions, so copies diverge.
  2. Editors of one document connect to different servers with no single order.
  3. Saving the whole document on every keystroke, and no history.
  4. Cursors sent at full rate to everyone.
  5. What happens when the document's server dies.

9. Make it hold up

9.1 Merging concurrent edits convergence

ApproachWhy
✗ BadLock the document (or paragraph) while someone types, or keep the last writeLocks make collaboration feel broken; last-write-wins silently throws away someone's typing.
~ GoodSend edits as positions ("insert s at 3") and apply them as they arriveWorks while edits don't overlap in time. As soon as two people edit concurrently, positions shift under each other and the copies diverge. Try it in section 13.
✓ GreatOperational transformation (OT) with a central server ordering ops, or a CRDT that gives every character a unique idOT rewrites each incoming op against concurrent ones ("insert at 3" becomes "insert at 5" because two letters were inserted before it). A CRDT refers to characters by id ("insert after t#3"), so concurrent ops commute and never need rewriting.

9.2 One document, one server convergence

Transforming ops needs one place that sees every op of a document in order. Route all sessions of a document to the same document server (consistent hashing on the document id, with a lease so only one server owns it; Module 21). That server loads the latest snapshot plus recent ops into memory, assigns revision numbers, transforms, appends to the op log, then broadcasts. Gateways hold the WebSockets and forward a document's messages to its owner.

9.3 Op log, snapshots and history durable

9.4 When a document server dies durable

Its lease expires; another server takes it and rebuilds the document from the latest snapshot and the log. Clients reconnect, send their base revision, receive the ops they missed, and resend their unacknowledged ops; duplicates are recognised by a client op id, so an op that was logged but not acknowledged isn't applied twice. A fencing token (the lease number) stops a slow old owner from appending after it lost the lease.

9.5 Presence, offline and permissions speed

Cursors and selections are frequent and disposable: broadcast them through the document server, throttle them to a few a second, and never store them. Offline edits queue on the client and are sent as ops with their old base revision when the connection returns; OT or the CRDT merges them like any other concurrent edit. Permissions are checked when the session opens and on every op (a viewer's ops are rejected).

9.6 Very busy documents scale

A doc with hundreds of editors concentrates load on one server. Batch keystrokes for ~50 ms (several times fewer ops, no visible lag), throttle presence harder, and serve pure viewers from a read-only stream fanned out by the gateways instead of the owner.

9.7 The whole design after the deep dives

Two concurrent edits through the final design. Press Play or drag the timeline.

10. Interviewer follow-ups

OT or CRDT: which would you pick?

For a cloud editor with a server anyway, OT (or a server-ordered approach) keeps documents compact. For offline-first or peer-to-peer, a CRDT. Mature libraries matter more than theory: say which you'd use and why.

How does undo work?

Undo is your own last op, inverted and transformed against everything since, so it undoes only your change, not someone else's.

A user is offline for a week.

Their ops are based on an old revision; the server transforms them against a week of ops (or the CRDT merges them). If that's too costly, show a merge view.

Search across documents.

Index snapshots asynchronously into a search engine, with the document's ACL, a few seconds behind.

Comments anchored to text.

Anchors are positions too, so they're transformed like ops (or anchored to CRDT character ids).

Multi-region.

Each document has a home region where its owner runs; users far away have higher latency for others' edits, but their own typing is still instant locally.

Variation: a shared whiteboard

"Design a collaborative whiteboard" (sticky notes, shapes, arrows on an endless canvas) reuses the one-server-per-document design above, but the document is a different shape, and that makes merging much simpler.

Read more: Figma's posts on how its multiplayer editing works and ordering objects with sortable keys.

11. When things break

FailureWhat users seeHow we detect itWhat limits the damage
Document server diesA second's pauseLease expiryNew owner rebuilds; clients resend
Gateway diesReconnectSocket dropClient reconnects with its base revision
Op log slowEdits wait for acksAppend latencyLocal typing stays instant; acks queue
Divergence bugDifferent text on two screensPeriodic checksum of copiesClient reloads from the server's snapshot

12. Wrap-up and the clock

Trade-offs we made:

What we'd watch:

At 10×:

A 45-minute interview

0–4Frame the problem (editors per doc, offline, history)
4–9Must do, how well, numbers
9–12Nouns, contract, data flow
12–18First working version, parked list
18–40Deep dives: merging (9.1), one owner (9.2), op log (9.3), failover (9.4)
40–45Follow-ups and wrap-up

A 60-minute interview

0–5Frame the problem
5–11Must do, how well, numbers
11–15Nouns, contract, data flow
15–23First working version
23–50Deep dives 9.1–9.6 and the final picture
50–60Follow-ups: OT vs CRDT, undo, offline; wrap-up
LevelWhat a strong answer shows
Mid-levelWebSockets, a server that broadcasts edits, a database for documents, and awareness that concurrent edits conflict.
SeniorOT or CRDT explained with an example, one server per document via consistent hashing, revision numbers and acks, op log plus snapshots, presence kept in memory.
Staff+OT vs CRDT trade-offs for the product (offline, rich text, scale), server failover and leases, compaction and history, very large and very busy documents, permissions on every op.

Common mistakes:

13. Try it, check yourself, read more

Alice and Bob start with the same text and make one edit each at the same moment. Each edit is applied locally at once (blue for Alice, green for Bob), then travels through the server to the other person.

Why does sending raw positions ("insert at 3") break with two editors?

After Bob inserts at the start, Alice's position 3 points at a different letter on Bob's copy.

How does a CRDT avoid transforming operations?

"Insert after character t#3" means the same thing on every copy, whatever else happened.

Why route all editors of a document to one server?

OT needs a single order of operations; one owner per document provides it.

What does opening a years-old document read?

Snapshots every N ops keep opening fast; the log still holds full history.
ResourceWhy
What's different about the new Google Docs: conflict resolution (Google)OT explained with examples by the team that built it.
How Figma's multiplayer technology works (Figma)A central-server design inspired by CRDTs.
crdt.techPapers, talks and libraries about CRDTs.