Skip to content

Collaborative Editing System Design: OT vs CRDT, Presence and Sync

How real-time collaborative editors work: operational transformation vs CRDTs, document session servers, presence, persistence and offline edits, with a diagram.

· Founder & developer

Published

Two clients connect over WebSocket through a load balancer to session server A, which owns doc-123 according to a Redis directory. Server A appends edits to a Postgres op log, writes snapshots to object storage and checks access with an identity provider. Server B owns other documents.

Two people type into the same paragraph at the same moment. Within a fraction of a second, both screens show the same text, and neither person's words have vanished. Making that work means solving one specific problem, concurrent edits to shared state, plus a set of ordinary infrastructure problems: routing, persistence, presence and reconnection.

This post designs a real-time collaborative editor: the concurrency problem on a worked example, operational transformation (OT) and conflict-free replicated data types (CRDTs) compared, the server-authoritative approach Figma uses, and the architecture around them, with a diagram.

The core problem, in five characters

Start with the document ABC. Positions count from zero.

  • Alice inserts X at position 1, giving AXBC on her screen.
  • At the same moment, Bob deletes position 2, the C, giving AB on his.

Each client now receives the other's operation and applies it as is:

  • Bob applies "insert X at 1" to AB and gets AXB.
  • Alice applies "delete position 2" to AXBC and deletes the B, getting AXC.

The documents have diverged, and Alice's copy lost a character nobody deleted. Every collaborative editor exists to prevent this. There are two families of solutions.

Operational transformation

OT keeps operations as positions and transforms each incoming operation against the concurrent operations it has not seen. Bob's "delete position 2" was made before Alice's insert at position 1, which shifts everything after it one place to the right. Transformed against the insert, it becomes "delete position 3", and Alice's AXBC becomes AXB, matching Bob.

Production OT systems use a central server to order operations, an approach that goes back to the Jupiter system in 1995 and that Google Docs described when it rebuilt its editor in 2010:

  1. Each client sends its operations tagged with the server revision they were based on.
  2. The server transforms each operation against everything it accepted since that revision, assigns the next revision number and broadcasts the result.
  3. Each client transforms incoming operations against its own unacknowledged ones.

OT's strengths are compact operations and a long track record for text. Its weakness is the transformation functions themselves: for rich text, tables and nested structures, getting every pair of operation types right is notoriously hard, and the design depends on a server to define the order.

CRDTs

A CRDT is a data type designed so that concurrent updates can be applied in any order and every replica still converges, formalized by Shapiro and colleagues in 2011. For text, each inserted character gets a unique, ordered identifier, such as a client ID and a counter, and an insert says "after the character with ID such-and-such" instead of "at position 1". Deletes mark characters as removed, leaving tombstones. Because operations refer to stable IDs rather than shifting positions, there is nothing to transform.

In the example, Alice's insert says "X goes after A", and Bob's delete says "remove C". Applied in either order, both replicas end up with AXB.

CRDT libraries such as Yjs and Automerge make this practical. Their strengths: no central ordering is required, so offline editing and peer-to-peer sync work naturally, and merging is possible at any time. Their costs: extra metadata per character, tombstones that must be compacted, and edge cases where the merged result is consistent but not what either user intended. A server is still useful for access control, persistence and fan-out; it just does not have to decide the order.

The server-authoritative middle way

Not every editor edits long text. Figma chose neither classic OT nor true CRDTs: its server defines the order of events, documents are trees of objects with properties, and when two people change the same property of the same object, the last value the server receives wins. Its servers run a separate process for each multiplayer document, and everyone editing that document connects to it. For design tools, spreadsheets and boards, where conflicts are per property, this is simpler than either alternative.

Operational transformation CRDT Server-ordered, last writer wins per property
Who orders edits Central server Nobody; merges commute Central server
Offline editing Limited Natural Limited
Metadata overhead Low Higher, per element Low
Hard part Transformation functions Compaction and intent Choosing conflict granularity
Fits best Rich text with a server Offline-first and peer-to-peer apps Objects with properties: design tools, boards

The architecture

Whichever algorithm you pick, the surrounding system looks similar:

  1. Clients connect over WebSocket to a collaboration service and keep the connection open while the document is open.
  2. One session server owns each document. All clients of doc-123 must reach the same server, so it can order or merge edits in memory. A directory, for example in Redis, maps documents to servers with a lease, and the load balancer or a routing layer sends connections there. Consistent hashing on the document ID works too, as long as two servers can never both believe they own a document.
  3. The session server holds the live document in memory, applies each incoming edit, and broadcasts it to the other clients.
  4. Every edit is appended to a durable op log before the server acknowledges it. A periodic snapshot of the whole document goes to object storage, so loading a document means reading the latest snapshot plus the operations after it.
  5. Permissions are checked on connect and on every operation; a viewer's edit is rejected, not merely hidden.

Comments, version history, search and export are separate services that consume the op log; they do not belong on the real-time path.

Presence is different data

Cursors, selections and "who is here" change constantly, matter only right now and are worthless a minute later. Treat presence as ephemeral: broadcast it through the same session server, throttle it to a few updates per second per user, drop it when a client disconnects, and never write it to the op log. Yjs, for example, keeps presence in a separate awareness channel next to the document state.

Offline edits and reconnection

Connections drop all the time, on trains and in elevators. The client keeps unacknowledged operations locally and resends them on reconnect:

  • With OT, the client sends its pending operations with the last revision it saw; the server transforms them against everything since.
  • With CRDTs, client and server exchange compact summaries of what each has seen, often called state vectors, and send each other only the missing updates.

Long offline periods are where CRDTs shine. With OT, a client that was offline for a day can still reconnect, but the server has a day of operations to transform against.

Scaling and failure

  • Hot documents. A document with thousands of viewers and a few editors should not make the session server push every keystroke to thousands of sockets itself; fan out to viewers through a pub/sub layer and batch updates.
  • Session server crash. Clients reconnect, the directory lease expires, a new server loads the snapshot and the op log, and clients resend their pending operations. Acknowledging only durably logged edits is what makes this lossless.
  • Split brain. Two servers owning the same document would accept conflicting orders. Fence ownership with the lease and reject writes from a server whose lease has expired.
  • Undo must undo your own last change, not your collaborator's, so it becomes a new inverse operation, transformed or merged like any other.

The collaboration diagram

Two clients connect over WebSocket through a load balancer to session server A, which owns doc-123 according to a Redis directory. Server A appends edits to a Postgres op log, writes snapshots to object storage and checks access with an identity provider. Server B owns other documents.

11 components · 9 connections

Open in Archboard
Diagram contents
  • Alice: editor
  • Bob: editor
  • WebSocket entry
  • Collaboration service
  • Directory: doc-123 → A (lease)
  • Session server A
  • Session server B
  • Op log
  • Snapshots
  • Identity provider
  • edits + presence
  • doc-123 sessions
  • who owns doc-123?
  • renew lease
  • append, then ack
  • snapshot
  • check access on connect
  • other documents
A real-time collaboration backend. Every client of a document connects over WebSocket to the one session server that owns it; that server orders or merges edits, broadcasts them with presence, and persists an op log plus periodic snapshots.

How to read it:

  • Two clients connect over WebSocket through the load balancer.
  • The Redis directory says which session server owns doc-123; both connections land on server A.
  • Server A orders or merges edits in memory and broadcasts edits and presence back to both clients.
  • Durability: every edit goes to the op log in Postgres before it is acknowledged; snapshots go to object storage.
  • The identity provider checks access when clients connect; server B owns other documents and shows how the service scales out.
  • The Markdown block compares OT and CRDTs in three lines.

Drawing real-time systems clearly

  • Show ownership. The single most important fact here is that one server owns one document; draw the directory and the routing.
  • Separate durable and ephemeral data. Draw the op log and snapshots, and label presence as not persisted.
  • Draw at least two clients. Concurrency is the whole problem; one client hides it.
  • Mark the acknowledgement point: an edit is safe once it is in the op log.

For long-lived connections and fan-out, the chat app architecture diagram covers similar ground. Routing documents to servers is an application of the ideas in the load balancer diagram, and the general method is in the system design diagram example.

Build it in Archboard

  1. Sign in with Google or GitHub and create a diagram.
  2. Add two Device nodes from the Network pack for the clients and a Cloud LB from the Cloud pack for WebSocket entry.
  3. Add a Core Frame for the collaboration service with two Compute nodes inside: session server A, owning doc-123, and session server B.
  4. Add a Redis node from the Data pack for the document directory, a Postgres node for the op log and an Object Storage node from the Cloud pack for snapshots.
  5. Add an Identity Provider from the Security pack, and connect everything with labeled edges: WebSocket, edits and presence, append, snapshot, lease.
  6. Add a Markdown block from the Core pack with the OT versus CRDT summary.

The example uses 11 diagram nodes, within the Free plan.

FAQ

What is the difference between OT and CRDT? OT transforms concurrent operations against each other, usually with a server defining the order. CRDTs give every element a stable identity so operations commute and replicas converge in any order, without central ordering.

Does Google Docs use OT or CRDTs? Google described its 2010 editor rewrite as using operational transformation, with a server ordering changes. Many newer editors use CRDT libraries such as Yjs or Automerge.

Why must all editors of a document connect to the same server? That server holds the live document and decides the order of edits. If two servers accepted edits for one document independently, they would need to coordinate on every keystroke.

How is presence stored? Mostly it is not. Cursors and selections are broadcast in real time, throttled, and dropped when a client disconnects. Persisting them adds load and no value.

Can a collaborative editor work offline? Yes. Clients queue operations locally and sync on reconnect. CRDTs handle long offline periods most naturally; OT works too but transforms more operations on return.

Start free — one seat, no credit card.

Related posts

← Back to blog

Open a canvas in a minute

Sign in with Google or GitHub. Free for a single seat. Upgrade when the team joins.