Real-Time Systems

CRDT vs OT: Real-time Data Synchronization Explained

Dive deep into CRDTs and Operational Transformation for real-time data synchronization. Understand their architecture, trade-offs, and use cases with code examples.

Khader Vali July 9, 2026 6 min read

CRDT vs OT: Real-time Data Synchronization Algorithms Explained

As a senior software engineer, few challenges are as intriguing and complex as achieving seamless real-time data synchronization across multiple users and devices. Think about collaborative document editing, multiplayer games, or even shared whiteboards – these applications demand that changes made by one user are immediately, and consistently, reflected for everyone else, regardless of network latency or concurrent modifications. This isn’t just about speed; it’s about maintaining a coherent, consistent state across a distributed system.

The quest for robust real-time synchronization has led to the development of sophisticated algorithms. Among the most prominent are Operational Transformation (OT) and Conflict-free Replicated Data Types (CRDTs). While both aim to solve the same fundamental problem, they approach it with vastly different philosophies, leading to distinct architectural patterns, trade-offs, and ideal use cases.

In this comprehensive article, we’ll dive deep into the mechanics of both OT and CRDTs. We’ll explore their core principles, walk through their architectural considerations, provide practical code examples, discuss their advantages and disadvantages, and ultimately help you understand when to choose one over the other. By the end, you’ll have a solid grasp of these powerful algorithms and be better equipped to design your next real-time collaborative system.

The Challenge of Real-time Consistency

Before we dissect OT and CRDTs, let’s briefly frame the problem they solve. Imagine two users, Alice and Bob, editing the same document simultaneously. Alice types “Hello” and Bob types “World” at roughly the same time, but at different positions. What happens if Alice’s change arrives at Bob’s client *before* Bob’s client sends its own change to the server, and vice versa?

Without a proper synchronization mechanism, both clients might apply their local changes and then attempt to apply the remote change, leading to a phenomenon known as “divergence.” The document state on Alice’s machine could be “Hello World” while on Bob’s it’s “World Hello,” or even “HelloHello WorldWorld” if operations are naive appended without context.

The core challenge is managing concurrent operations that originate from different sources, arrive out of order, and might conflict. We need a way to ensure that eventually, all replicas of the data converge to the same, correct state, and that this convergence happens deterministically and transparently to the user.

Operational Transformation (OT): The Pioneer of Collaboration

Operational Transformation is a technique that emerged in the late 1980s and gained significant popularity with the advent of collaborative text editors like Google Docs. Its fundamental idea is to transform (adjust) an operation before applying it, ensuring that it remains consistent with the document state that has already incorporated concurrent operations.

How OT Works: The Core Idea

At its heart, OT operates on a sequence of operations. When a client performs an action (e.g., inserting a character, deleting a word), it generates an “operation” describing that change. This operation, along with the version of the document it was based on, is sent to a central server. The server then coordinates transformations and broadcasts the transformed operations to other clients.

The magic happens in the transformation function. When two operations, say OpA and OpB, are generated concurrently on different states of the document, applying them sequentially in any order (OpA then OpB, or OpB then OpA) would lead to different results. The transformation function, T(OpA, OpB), takes OpA and transforms it into OpA' such that applying OpA' to a document that has already incorporated OpB yields the same result as applying OpB then OpA to the original document. Similarly, T(OpB, OpA) transforms OpB to OpB'.

This is often illustrated with the “Transformation Matrix” or “Transformation Properties”:

  • Commutativity: For any two operations O1 and O2, if O1 transforms O2 to O2′, and O2 transforms O1 to O1′, then applying (O1 then O2′) should yield the same result as (O2 then O1′). This is the core property that OT strives for.
  • Inclusion Transformation (IT): When an operation O_remote arrives at a client, and the client has unacknowledged local operations O_local, O_remote must be transformed against O_local to create O_remote'. This O_remote' can then be applied to the client’s current state, which already includes O_local.
  • Exclusion Transformation (ET): This is the inverse of IT, used less frequently but important for certain undo/redo scenarios.

OT Architecture: Centralized Control

A typical OT system relies on a central server to mediate all operations. This server acts as the single source of truth and is responsible for maintaining the canonical version of the document and orchestrating transformations.

Here’s a simplified flow:

  1. Client A sends Operation: Alice makes a change (e.g., inserts ‘x’ at index 5). Her client generates OpA = (insert 'x' at 5), noting it’s based on document version V_N. It applies OpA locally and updates its own state.
  2. Server Receives and Transforms: The server receives OpA. It has its own canonical document state, say at version V_M.
    • If V_N == V_M, OpA is applied directly to the server’s state, incrementing the version.
    • If V_N < V_M (meaning other operations have already been applied to the server’s state since V_N), the server must transform OpA against all intervening operations (Op_N+1, …, Op_M) to get OpA'. This OpA' is then applied to the server’s V_M state.
  3. Server Broadcasts: After applying the transformed operation, the server broadcasts OpA' (along with the new version V_M+1) to all other connected clients (e.g., Bob).
  4. Client B Receives and Transforms: Bob’s client receives OpA'.
    • If Bob has no pending local operations, he applies OpA' to his current state.
    • If Bob *does* have pending local operations (e.g., OpB, which he sent to the server but hasn’t received an acknowledgment for yet), he must transform OpA' against his own OpB to get OpA''. He then applies OpA'' to his state. This ensures that when his OpB is eventually acknowledged and reflected from the server, it harmonizes with OpA'.
CRDT vs OT: Real-time Data Synchronization Explained
Generated Image

Diagram in words for OT Architecture:

        +----------------+     Operation(OpA, V_N)     +--------+
        |  Client A      | --------------------------> | Server |
        |  (local state) |                             | (canonical|
        |                | <-------------------------- |  state,  |
        +----------------+     Ack/Transformed OpA'    |  history)|
                ^                                        |        |
                |                                        +--------+
                |                                            |
                |                                            | Transformed OpA'
                |                                            |
                |                                            V
        +----------------+     Transformed OpA''       +----------------+
        |  Client B      | <-------------------------- |  Client B      |
        |  (local state, |                             |  (local state) |
        |  pending ops)  | <-------------------------- |                |
        +----------------+                             +----------------+
        (Client B also sends its own Ops to Server, similar to Client A)

        Flow Description:
        1. Client A generates OpA based on its current state (V_N) and applies it locally.
        2. Client A sends OpA and V_N to the Server.
        3. Server receives OpA. It transforms OpA against any operations it has already processed that Client A hasn't yet seen (i.e., operations between V_N and the server's current version). This results in OpA'.
        4. Server applies OpA' to its canonical state, increments its version, and broadcasts OpA' (with the new version) to all other clients, including Client B.
        5. Client B receives OpA'.
        6. If Client B has local pending operations (OpB), it transforms OpA' against its local OpB to get OpA''.
        7. Client B applies OpA'' to its local state. It also sends its own OpB to the server, and the server will transform OpB against OpA' if OpA' arrived at the server first.
    

OT Code Example: Simplified Text Operations

Implementing a full OT system is notoriously complex due to the intricate logic of transformation functions for various operation types (insert, delete, replace). However, let's illustrate a simplified transformation for text insertions.

Assume an operation is { type: 'insert', index: N, text: 'chars' }.
The goal of transform(op_local, op_remote) is to adjust op_local so it can be applied to a state that *already* has op_remote applied.

class TextOp {
constructor(type, index, value) {
this.type = type; // 'insert' or 'delete'
this.index = index;
this.value = value; // character or string
}

// A very simplified transformation function for two insertion operations
// In a real OT system, this would be much more complex, handling
// delete operations, relative indices, and the full matrix of transformations.
transform(op_this, op_other) {
if (op_this.type

Written by

Khader Vali

Senior Software Engineer specializing in cloud architecture, real-time systems, and enterprise-scale applications.

Share this article

Related Articles

WebTransport & WebRTC: Next-Gen Real-Time Web Communication

Jul 14, 2026 · 7 min read

WebTransport & WebRTC: Next-Gen Real-Time Web Communication

Jul 04, 2026 · 6 min read

WebSocket Scaling Patterns for 100K+ Concurrent Connections

May 12, 2026 · 2 min read