Real-Time Collaborative Apps with CRDTs and WebSockets
Building multiplayer text editors like Google Docs, Figma, or Notion requires synchronizing concurrent modifications from multiple users across high-latency network connections. Traditional server-side locking or centralized relational transactions fail under real-time requirements because latency and lock contention destroy the user experience.
Conflict-free Replicated Data Types (CRDTs) solve concurrent state mutation mathematically. By modeling data structures so that operation ordering does not affect the final state, CRDTs allow multiple clients to edit local copies concurrently without central server coordination, guaranteeing eventual convergence when updates arrive. Combined with bi-directional WebSockets, CRDTs enable instant local updates and reliable background synchronization.
Operational Transformation vs CRDTs
For decades, collaborative text editing relied on Operational Transformation (OT) — the technology powering early Google Docs. OT works by transmitting operations (insert, delete) to a central server, which transforms incoming position offsets relative to concurrent operations before broadcasting them to other clients. While effective, OT requires a single authoritative server to compute transformations and maintain strict operation sequencing.
In contrast, CRDTs achieve consistency decentralised without requiring a central server to transform operations. CRDT data structures (such as Yjs or Automerge) attach unique deterministic identifiers — such as fractional index strings or Lamport timestamps — to every element. Because item IDs determine ordering independently of when operations arrive, concurrent updates can be merged in any order on any client to produce the exact same final state.
This structural independence simplifies architecture: the server acts purely as a dumb relay broker or WebSocket router, reducing server CPU utilization and eliminating central bottlenecks. For deeper context on distributed locks and concurrency primitives, explore our comparison of Redis Redlock vs etcd vs ZooKeeper.
Quick reference
- OT depends on a central server to transform operation offsets sequentially.
- CRDTs assign global unique IDs to elements, ensuring deterministic merge across all nodes.
- CRDT servers act as simple message brokers without needing to execute business logic.
- CRDTs enable local-first offline editing and peer-to-peer (WebRTC) synchronization.
- Mathematical commutativity, associativity, and idempotency guarantee state convergence.
Remember this
CRDTs replace complex server-side transformation loops with client-side mathematical convergence.
State-Based vs Operation-Based CRDT Mechanics
CRDT implementations generally fall into two architectural categories: State-based (CvRDT) and Operation-based (CmRDT). Understanding the distinction dictates payload sizes, network protocols, and garbage collection strategies.
State-based CRDTs (Convergent) transmit the full state of the data structure between replicas. Replicas merge incoming full states using a join semi-lattice operator $\\sqcup$ that is commutative ($A \\sqcup B = B \\sqcup A$), associative ($A \\sqcup (B \\sqcup C) = (A \\sqcup B) \\sqcup C$), and idempotent ($A \\sqcup A = A$). State-based CRDTs are resilient against network packet loss or duplication, but bandwidth grows as the total dataset size expands.
Operation-based CRDTs (Commutative) transmit individual fine-grained operations (e.g., 'insert char X at ID 4.2'). Operations must be delivered across the network exactly-once and in causal order. CmRDT payloads are orders of magnitude smaller than full-state transfers, making them ideal for continuous low-latency WebSocket messaging in real-time collaborative text and canvas applications.
Quick reference
- State-based (CvRDTs) send full payload snapshots; merge function is idempotent.
- Operation-based (CmRDTs) send delta operation streams; requires causal transport.
- Yjs and Automerge use hybrid delta-state encodings for optimal memory & network usage.
- Lamport clocks and vector clocks preserve causality across asynchronous clients.
- Garbage collection of tombstone markers is required to keep long-lived documents lightweight.
Remember this
Operation-based CRDTs optimize network bandwidth for real-time collaboration, while state-based CRDTs simplify periodic snapshot recovery.
WebSocket Transport & Multi-Peer State Sync
To connect clients executing CRDT state updates, applications establish persistent bi-directional WebSocket connections to a pub/sub messaging gateway. Upon connecting, a client exchanges state vectors with the server to determine missing binary updates through a two-step handshake.
First, Client A sends its local State Vector — a compact dictionary summarizing the latest sequence number received for every active client ID. The server compares Client A's vector against the document's canonical state and returns only the missing binary delta updates. Client A applies the updates locally to catch up instantaneously.
Second, as Client A types, local changes are encoded into compact binary update chunks (e.g., using Y.encodeStateAsUpdate) and pushed over the WebSocket connection. The gateway broadcasts the binary update chunk to all other subscribed clients on the document channel. Because CRDT updates are idempotent, network retries or out-of-order deliveries never corrupt state.
Quick reference
- State Vectors allow nodes to compute delta updates without transferring whole documents.
- Binary encodings (protobuf/lib0) reduce CRDT update payloads to a few bytes per keystroke.
- WebSocket servers broadcast binary chunks to channel subscribers without decoding payloads.
- Reconnection logic automatically re-sends state vectors to reconcile missing off-line updates.
- Presence & Awareness protocols share cursor positions and selections out-of-band.
Remember this
State vectors eliminate expensive diff calculations, letting WebSockets sync updates using minimal network bandwidth.
Handling Offline Edits & Eventual Convergence
A key benefit of CRDT architecture is native support for Local-First / Offline-First operation. When a user loses internet connectivity in a tunnel or airplane, local edits continue writing to an IndexedDB or SQLite storage layer seamlessly.
While offline, the local CRDT engine records all document operations in an immutable local delta log. When network connectivity is restored, the client reconnects to the WebSocket gateway, transmits its accumulated delta log, and fetches any server updates missed during the offline window. Both the client and server execute Y.applyUpdate, converging on the identical document state automatically.
To prevent infinite log growth, systems establish periodic Snapshot Compaction. The server merges historical operation logs into a single base snapshot state, discarding obsolete deletion tombstones while preserving active document structure. For theoretical grounding on network availability trade-offs during partitions, consult our CAP theorem guide.
Quick reference
- IndexedDB persists local CRDT updates locally for instant offline startup.
- Reconnection triggers state vector exchanges to sync offline edits bi-directionally.
- Eventual convergence guarantees all peers reach identical document states regardless of latency.
- Snapshot compaction prunes old tombstones to optimize long-term memory footprint.
- Conflict resolution is deterministic — no manual conflict resolution UI prompts are needed.
Remember this
CRDTs deliver true local-first responsiveness with zero-conflict automatic server convergence upon reconnection.
Key takeaway
To test CRDT synchronization under real-world network conditions, disconnect a browser tab's network via Chrome DevTools while editing text. Make 20 typing edits offline, re-enable the network, and verify that both tabs converge on identical character sequences.
Related Articles
Explore this topic