Last modified: March 23, 2026
This article is written in: 🇺🇸
Operational Transform is a foundational technique in distributed systems that enables real-time collaborative editing of shared documents. Originally proposed by Ellis and Gibbs in 1989, OT allows multiple users to concurrently modify the same document while preserving consistency across all participants. The core idea is to transform incoming operations against previously executed operations so that every replica converges to the same final state regardless of the order in which edits arrive.
[User A] [User B] [User C]
| | |
| op_a: Insert("X",3) | op_b: Delete(5) | op_c: Insert("Z",1)
| | |
v v v
+-----------+ +-----------+ +-----------+
| OT Engine |<------>| OT Engine |<------->| OT Engine |
| (Client) | | (Client) | | (Client) |
+-----------+ +-----------+ +-----------+
\ | /
\ | /
\ v /
\ +-----------------+ /
+------>| OT Server |<------+
| (Central Relay) |
+--------+--------+
|
v
+-------------------+
| Shared Document |
| "Hello, World!" |
+-------------------+
Collaborative editing introduces several fundamental problems in distributed systems:
User A (Local State) User B (Local State)
"ABCD" "ABCD"
| |
| Insert('X', pos=2) | Delete(pos=3)
v v
"ABXCD" "ABD"
| |
|--- op_a sent over network ------->| (arrives late)
|<------ op_b sent over network ----| (arrives late)
| |
| Naive apply Delete(pos=3) | Naive apply Insert('X', pos=2)
v v
"ABCD" (WRONG! Lost 'X') "ABXD" (DIFFERENT! Inconsistent)
OT resolves conflicts by transforming each incoming remote operation against local operations that have already been applied. This transformation adjusts positions and parameters so the intent of every edit is preserved.
The transformation process follows these steps:
User A: Insert('X', pos=2) User B: Delete(pos=3)
on document "ABCD" on document "ABCD"
Transform Function: T(op_a, op_b)
+-------------------------------+
| Input: |
| op_a = Insert('X', pos=2) |
| op_b = Delete(pos=3) |
| |
| Logic: |
| op_a.pos <= op_b.pos |
| so shift op_b.pos by +1 |
| |
| Output: |
| op_a' = Insert('X', pos=2) |
| op_b' = Delete(pos=4) |
+-------------------------------+
User A applies op_b': Delete(pos=4) User B applies op_a': Insert('X', pos=2)
"ABXCD" -> "ABXD" "ABD" -> "ABXD"
^ ^
Both converge to "ABXD"
The transform function T(op_a, op_b) takes two concurrent operations and returns adjusted versions that can be safely applied in either order. Below is a simplified example for insert-vs-insert and insert-vs-delete cases:
T(Insert(pos_a), Insert(pos_b)):
+-----------------------------------------+
| if pos_a < pos_b: |
| return Insert(pos_a), Insert(pos_b + 1) |
| else if pos_a > pos_b: |
| return Insert(pos_a + 1), Insert(pos_b) |
| else: (tie-break by user ID) |
| if user_a < user_b: |
| return Insert(pos_a), Insert(pos_b + 1) |
| else: |
| return Insert(pos_a + 1), Insert(pos_b) |
+-----------------------------------------+
OT systems define a set of primitive operations that cover all possible document mutations:
For an OT system to guarantee correctness, the transform function must satisfy key mathematical properties:
a and b, applying a then T(b, a) must yield the same state as applying b then T(a, b). This ensures pairwise convergence.TP1 Convergence Guarantee:
+---------------------------------------------------+
| |
| State S |
| | \ |
| | apply(a) \ apply(b) |
| v v |
| State S_a State S_b |
| | \ |
| | apply(T(b,a)) \ apply(T(a,b)) |
| v v |
| State S_ab === State S_ba (must be equal) |
| |
+---------------------------------------------------+
OT architectures fall into two main categories depending on how operations are coordinated across participants:
Server-based OT uses a central server as the single source of truth:
Peer-to-peer OT has no central authority:
Conflict-free Replicated Data Types (CRDTs) offer an alternative approach to collaborative editing. While OT transforms operations, CRDTs design data structures that merge automatically without conflicts.
| Aspect | OT | CRDT |
| Conflict Resolution | Transforms operations at runtime | Conflicts are impossible by design |
| Server Requirement | Often relies on a central server | Works fully peer-to-peer |
| Complexity | Complex transform functions | Complex data structures |
| Memory Overhead | Low (stores operations) | Higher (stores metadata per character) |
| Proven at Scale | Google Docs, Apache Wave | Yjs, Automerge, Apple Notes |
| Correctness | Must satisfy TP1/TP2 (error-prone) | Mathematically guaranteed |
| Undo Support | Straightforward with inverse operations | More difficult to implement |
| Network Requirement | Typically needs ordered delivery | Works with any delivery order |
Key considerations when choosing between them:
Building an OT system requires careful attention to several engineering challenges:
Popular OT implementations include: