Introduction
The Type-Agnostic Operational Transformation Framework.
The Type-Agnostic Operational Transformation Framework.
OpenOT is a headless, type-agnostic Operational Transformation (OT) engine designed for developers who want to build real-time collaborative applications without being locked into a specific database, network transport, or rich-text editor.
Unlike other solutions that bundle the editor, the database, and the WebSocket server into a black box, OpenOT gives you the raw synchronization primitives to build anything from a collaborative code editor to a shared whiteboard or a real-time JSON configuration tool.
Building real-time collaboration is hard. You have to handle:
OpenOT solves these problems with a mathematically proven state machine that handles the complexity of OT, leaving you free to choose your stack.
OpenOT is split into three decoupled packages, allowing you to use only what you need.
@open-ot/core)The heart of the framework. It defines the OTType interface, which allows you to teach OpenOT how to synchronize any data structure.
export interface OTType<Snapshot, Op> {
name: string;
create(): Snapshot;
apply(snapshot: Snapshot, op: Op): Snapshot;
transform(opA: Op, opB: Op, side: "left" | "right"): Op;
compose(opA: Op, opB: Op): Op;
}If you can implement these four functions, you can collaborate on it. We provide a built-in TextType, but you can write types for JSON, XML, or your own custom binary format.
@open-ot/client)The client implements the standard OT state machine to handle the "hard parts" of synchronization. It manages three distinct states to ensure your UI never locks up, even on slow networks:
// It handles the complexity so you don't have to
client.applyLocal(op); // Updates local state immediately (optimistic UI)
// ... background magic handles sending, buffering, and rebasing ...@open-ot/server)The server is a lightweight coordinator. It doesn't care about your database. It uses an IBackendAdapter to fetch and store operation history.
const server = new Server(new RedisAdapter(redisUrl));It handles the "Catch Up" phase: if a client comes online with an old revision, the server transforms their operation against the history of changes they missed, ensuring the document never diverges.
OpenOT is designed to fit into your existing architecture, not replace it.
| Component | OpenOT Approach |
|---|---|
| Database | Pluggable. Use Redis, Postgres, MongoDB, or Durable Objects. Just implement getRecord and saveOperation. |
| Network | Agnostic. Use WebSockets, HTTP/2 SSE, WebRTC, or even email. If you can send a JSON blob, you can use OpenOT. |
| Editor | Decoupled. Bind it to Monaco, CodeMirror, ProseMirror, or a plain <textarea>. |
Check out the Quickstart to build your first collaborative app in under 5 minutes.