The big idea
What is a collaborative editor?
Two people open the same document and type at the same time. Each sees their own edits instantly and the other’s appear live, and somehow both end up looking at the exact same text. No “file is locked”, no overwriting each other’s work.
Stop syncing whole documents and start syncing tiny operations — “insert ‘x’ at position 5”. A server orders everyone’s ops and resolves conflicts so every copy converges to the same state. Get that one idea right and the rest is plumbing.
How to read this: We add one piece at a time, problem then fix, and the diagram grows. Hit Begin.
Step 1 · The model
Edits are operations
If a save means “upload the whole document”, two people’s saves clobber each other and the last one wins. You can’t merge intent from snapshots — by then the information about what changed is gone.
Design decision: Two people edit the same doc simultaneously. What does the client send on each change?
The call: Tiny operations: insert/delete at a position. — Model the doc as an ordered sequence and stream small ops applied locally for instant feedback. Ops preserve intent and are cheap to send, order and merge — the op stream is the source of truth.
Model the doc as an ordered sequence and every edit as a small op (insert/delete at a position). The editor applies ops locally for instant feedback and streams them to an Edit Server over a persistent connection.
Ops, not snapshots: Tiny operations preserve intent and are cheap to send, order, and merge. The document is just the result of applying the op stream — the stream is the source of truth.
Step 2 · The hard part
Resolving concurrent edits
A and B both edit from the same starting text. A inserts at position 2; B deletes at position 1. By the time A’s op reaches B, B’s positions have shifted — apply A’s op blindly and the docs diverge. Forever.
Design decision: A inserts at position 2; B deletes at position 1. By the time A’s op reaches B, positions have shifted. How do they stay identical?
The call: OT or CRDTs: transform/merge concurrent ops to converge. — OT rewrites an incoming op against ops it didn’t see (shift A’s "insert at 2" past B’s delete); CRDTs give each char a stable orderable id so edits merge commutatively. Both guarantee convergence — same ops, any order, same doc.
Use Operational Transformation (OT) or CRDTs. OT rewrites an incoming op against ops it didn’t see (shift A’s “insert at 2” to account for B’s delete). CRDTs give each character a stable, orderable ID so concurrent edits merge commutatively — no transform needed.
OT vs CRDT: OT centralizes ordering on a server and keeps ops small; CRDTs need no central transform but carry more per-character metadata. Both guarantee convergence: same ops, any order, same document.
Step 3 · Make it live
Broadcast to everyone
A’s edit is resolved on the server — but B is still staring at stale text. Collaboration only feels real if the other person’s changes show up in well under a second.
Design decision: A’s edit is resolved on the server, but B still sees stale text. How does B’s screen update live?
The call: Broadcast each accepted op over WebSockets (pub/sub across servers). — After accepting an op the server pushes it to every other editor’s open socket; when editors are on different servers, pub/sub relays it to whoever holds each connection. Real-time = push, not poll.
After accepting an op, the server broadcasts it to every other editor of the doc over their WebSockets. When editors sit on different servers, a pub/sub layer relays the op to whichever server holds each connection.
Persistent connections: Real-time means push, not poll. WebSockets keep a channel open both ways; a session registry (and pub/sub across servers) ensures an op reaches exactly the people editing that doc.
Step 4 · Never lose a keystroke
Persist: op log + snapshots
The live document lives in server memory. A crash, and hours of collaborative work vanish. But you also can’t rebuild a long doc by replaying millions of ops on every open.
Design decision: The live doc is in server memory and a long doc has millions of ops. How do you avoid losing work AND loading fast?
The call: Append ops to a durable log + periodic snapshots. — The append-only op log is the truth (nothing lost on a crash); periodic snapshots let you load the latest checkpoint and replay only ops since — fast recovery, full history, free version control.
Append every accepted op to a durable Op Log, and periodically write a Snapshot of the full state. To load a doc, take the latest snapshot and replay only the ops since — fast recovery, full history, and free version control.
Log + checkpoint: The append-only log is the truth; snapshots are a performance cache of it. This same pattern (event log + periodic materialization) shows up in databases and stream processors everywhere.
Step 5 · Who else is here?
Presence & cursors
Collaboration feels lonely — and people collide — if you can’t see where others are. Those colored cursors and name flags are core to the experience, but they’re high-frequency and disposable.
Design decision: Colored cursors and "3 people viewing" update constantly and are disposable. How do you handle them?
The call: A separate ephemeral path: broadcast presence, never persist it. — Track who’s connected and each cursor/selection, broadcast constantly, but never store it — if everyone leaves, presence evaporates while the doc remains. A cursor flood can’t risk the op log.
Track Presence separately from the document: who’s connected, and each person’s cursor/selection. Broadcast these constantly but never persist them — if everyone leaves, presence simply evaporates while the doc remains.
Ephemeral vs durable: Cursors and “3 people viewing” are throwaway state; the document is sacred. Keeping them on separate paths means a flood of cursor updates never risks or slows the durable op log.
Step 6 · The flaky network
Offline & reconnection
Connections drop in tunnels and on planes. A user keeps typing offline, then reconnects — meanwhile others changed the doc. Their queued edits must merge cleanly, not overwrite or get lost.
Design decision: A user edits offline in a tunnel, then reconnects — others changed the doc meanwhile. How do the edits merge?
The call: Client tracks its last version; sends buffered ops + pulls ops since. — On reconnect the client sends queued ops and pulls everything from the op log after its last-seen version; OT/CRDT merges the two streams. Offline editing is just real-time editing with a longer delay — same convergence machinery.
Each client tracks the last version it saw. On reconnect it sends its buffered ops and pulls everything from the Op Log since that version; OT/CRDT merges the two streams. The same convergence machinery that powers live editing powers catch-up.
Versions make sync trivial: Because the doc is an ordered op log, “sync” is just “give me ops after version N and transform mine against them”. Offline editing is only real-time editing with a longer delay.
Step 7 · Permissions & scale
The sharp edges
Not everyone may edit — some can only view or comment — and a viewer must not be able to sneak in an op. And a server can only hold so many live docs and connections before it tips over.
Check Permissions on join and on every op, so the server rejects edits from non-editors. Scale by sharding by document: all editors of one doc land on the same server (consistent hashing), keeping its in-memory state authoritative; pub/sub bridges across shards.
One doc, one owner server: Pinning a document to a single authoritative server avoids distributed consensus on every keystroke. Permissions enforced server-side mean the client is never trusted with what it’s allowed to do.
You did it
You just designed Google Docs.
- Edits are tiny operations on an ordered model, not whole-document saves.
- OT or CRDTs resolve concurrent edits so every copy converges.
- Accepted ops broadcast over WebSockets (and pub/sub) for live collaboration.
- A durable op log plus periodic snapshots give recovery, history and fast loads.
- Presence (cursors, who’s here) runs on a separate, ephemeral path.
- Versioned op logs make offline editing and reconnection sync just work.
- Server-side permissions and per-document sharding handle security and scale.