Design Google Docs (Collaborative Document Editor)
DifficultyHard | HelloInterview: problem breakdown
Problem Statement
Design a collaborative document editing system where multiple users can edit the same document simultaneously and see each other's changes in real-time, without conflicts.
๐Real-world: This problem birthed two competing algorithm families with a genuine history. Operational Transformation (OT) โ the approach Google Docs actually uses โ dates back to a 1989 research system (GROVE) and works by transforming concurrent edits so they apply consistently (if you insert at position 5 while I delete at position 2, the system rewrites your operation to land correctly). OT is powerful but notoriously hard to implement right โ Google engineers have said it took enormous effort to get correct. The challenger is CRDTs (Conflict-free Replicated Data Types), which structure the data so concurrent edits mathematically can't conflict and merge deterministically without a central server โ the foundation of newer tools like Figma and local-first apps. The interview decision is OT (server-coordinated, compact) vs CRDT (peer-friendly, heavier metadata). Security angle: real-time collab means fine-grained access control and per-keystroke audit โ who could see/edit which doc at which moment โ plus the WebSocket layer is its own attack surface.
Requirements
Functional
- Real-time collaborative editing (multiple users, same document)
- Persistent storage of document state
- Edit history / version control
- User presence (who's currently viewing/editing)
- Comments and suggestions
- Offline editing with sync on reconnect
Non-Functional
- 1B documents; 50M DAU
- Conflict resolution: users see consistent state within 100ms
- No data loss: every keystroke eventually persisted
- Highly available (offline mode works)
Core Design
The Central Challenge: Concurrent Edits
User A deletes character at position 5 while User B inserts at position 3. If applied in sequence, they corrupt each other's document state. How do you merge them correctly?
Operational Transformation (OT)
The original collaborative editing approach (used by Google Docs).
Key ideatransform an operation against concurrent operations so it remains correct when applied after them.
Initial: "Hello World"
User A: delete position 6 (delete 'W') โ "Hello orld"
User B: insert 'X' at position 6 โ "Hello Xorld"
Without transformation:
Apply A then B: "Hello Xorld" (correct)
Apply B then A: User A deletes 'X' instead of 'W' (wrong!)
With OT:
transform(delete_6, insert_6) โ delete_7 (shift A's operation by 1)
Apply B then transform(A): "Hello Xorld" โ delete pos 7 โ "Hello Xorld" โOT works well for single-type documents (text) but becomes complex for rich documents with many operation types.
CRDT (Conflict-free Replicated Data Type)
Modern approach (used by Figma, Notion, Linear).
Key ideadesign the data structure so concurrent operations can always be merged without conflict. Each character gets a globally unique ID; positions are logical (not integer indices).
Character IDs: A's insert gets ID (userA, seq1), B's gets (userB, seq1)
Order: determined by ID comparison, not position
โ Concurrent inserts at the same position have deterministic ordering by user ID
โ Merge is always possible, always correctPopular CRDTs: Yjs, Automerge (both open-source, production-proven).
OT vs CRDT
| OT | CRDT | |
|---|---|---|
| Complexity | Complex server-side transform logic | Complex data structure; simple merge |
| Server requirement | Central server coordinates transforms | Peer-to-peer possible; server optional |
| Performance | Lower storage overhead | Higher storage (character IDs) |
| Offline support | Hard | Native |
| Used by | Google Docs (original) | Figma, Linear, Notion |
Architecture
Client (browser/mobile)
- Local document state (CRDT or OT buffer)
- WebSocket connection to Collaboration Server
โ
Collaboration Server (stateful, per document)
- Maintains connected clients for each document
- Receives operations, transforms/merges, broadcasts
- Persists operations to Operation Log
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Operation Log (Kafka / DB) โ โ append-only, every edit
โ Document Snapshot Store (S3) โ โ periodic full snapshots
โ Session Store (Redis) โ โ who's connected, cursor positions
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโOperation Log + Snapshots
Storing every operation is expensive to replay from scratch. Periodic snapshots:
snapshot at version 1000 + operations 1001-1050 = current state at version 1050Compaction: after snapshot, old operations can be archived.
Presence and Awareness
Redis (per document):
doc:{doc_id}:users โ set of { user_id: cursor_position, color, name }
TTL: 30s (refresh on heartbeat)
WebSocket broadcast: when user moves cursor or selection changes,
broadcast to all other connected clients for the same documentKey Design Decisions
| Decision | Choice | Reason |
|---|---|---|
| Conflict resolution | CRDT (Yjs) | Offline support; no central coordinator needed |
| Real-time transport | WebSocket | Bidirectional; low latency |
| Persistence | Append-only operation log | History, replay, debugging |
| Snapshots | S3 + periodic compaction | Avoid full replay from op 0 |
| Presence | Redis pub/sub | Low latency broadcast; TTL-based cleanup |
Security Considerations
| Threat | Mitigation |
|---|---|
| Unauthorized edit | Document ACL check on every WebSocket message |
| Malicious operations (large inserts, spam) | Operation size limits; rate limiting per user |
| Content injection (XSS via doc content) | Sanitize rendered HTML; CSP; rich text renderer doesn't execute scripts |
| Exfiltration via shared link | Audit log of every share action; link revocation capability |
| Forged operations (client sends ops as another user) | Sign operations with server-issued session token; validate on server |
| Data loss | Durable operation log (Kafka replication); cross-region backup |
Interview Tips
this is the core of the problem. Know both at a high level; mention that Google Docs uses OT historically but modern systems prefer CRDTs.
is a key requirement โ CRDTs handle this natively; OT requires a central server, which is why offline is hard.
storing every operation forever is impractical; mention periodic snapshots + log compaction.
is a separate, simpler problem from the conflict resolution โ keep them distinct in your design.