system design

Low Level Design: Operational Transform Sync

OT for Text

Operations are insert(pos, text) and delete(pos, len). These two primitives cover every edit — a replacement is a delete followed by an insert — which is why the operation set stays this small. This is the foundation of any real-time collaborative editing system; interviewers often ask why the client sends operations instead of the whole document, and the answer is that character-level ops let concurrent edits merge instead of overwriting each other.

Transformation Function

transform(op1, op2) adjusts positions of concurrent ops to maintain convergence. Example: if op1 inserts before op2 position, op2 position shifts by op1.length. Interviewers probe the transform properties: TP1, where both sides converge to the same document after each applies the other’s transformed op, and TP2, the harder guarantee needed when the same pair of ops can be transformed in different orders. The edge cases that trip candidates up are two inserts at the identical position (you need a tie-breaker, usually the client id) and a delete whose range overlaps a concurrent insert.

Server Algorithm

Server serializes all ops; each client sends op with client_revision; server transforms against all ops since that revision. This central-server model is the version most teams ship, because it avoids the hardest peer-to-peer transform cases: the server is the single source of truth for ordering. In a system design interview, the detail to get right is that the server transforms the incoming op against the exact suffix of the op log after client_revision, applies it, then assigns the next revision number and returns it as an acknowledgement.

Data Schema

Document Table

Document (
  id UUID,
  content TEXT,
  revision INT
)

Operation Table

Operation (
  id UUID,
  doc_id UUID,
  revision INT,
  type ENUM(insert, delete),
  position INT,
  text TEXT,       -- for insert
  length INT,      -- for delete
  client_id TEXT,
  created_at TIMESTAMP
)

Operation Flow

Client sends op
  → Server receives
  → Transform against ops since client_revision
  → Apply to document
  → Broadcast transformed op to other clients

Client receives server op
  → Transform against pending local ops
  → Apply

Diamond Problem

op1 and op2 concurrent: server applies op1, transforms op2 against op1, sends transformed op2 to client who sent op1; client transforms op2 against their pending ops. The subtle part interviewers watch for is the client’s own in-flight ops: an op that has been sent but not yet acknowledged must still be transformed against the incoming server op, or the two replicas drift apart. Tracking that pending queue correctly is what separates a working implementation from one that silently corrupts the document.

Cursor Position Preservation

Cursor ops transformed alongside text ops to maintain correct cursor positions for all participants. A concrete case interviewers like: when a remote insert lands before your cursor, your cursor must shift right by the inserted length, but an insert at the exact cursor position needs a rule for whether the cursor stays put or moves — otherwise two users typing at the same spot see their carets jump unexpectedly.

See also: Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence

See also: Atlassian Interview Guide

See also: Meta Interview Guide 2026: Facebook, Instagram, WhatsApp Engineering

newsletter

What's actually being asked right now

Interview patterns & comp trends, straight to your inbox.

No spam. Unsubscribe anytime.

newsletter

What's actually being asked right now

Interview patterns & comp trends, straight to your inbox.

No spam. Unsubscribe anytime.

1972 Soviet postage stamp commemorating the Mars 2 probe

worth a read

Mars For The Rest of Us — a weekly-or-more deep dive on the technical side of Mars exploration: rocket propulsion, microbiology, mission architecture, and everything in between. Written by Maciej Ceglowski.

Read it on Substack →
Scroll to Top