Persistence

Strategies to persist and sync a Doc

This page covers practical ways to persist a Doc on a server. DocNode uses an OT-style model: all clients must apply operations in the same order to converge, or the server can send back a full document snapshot.

Strategy 1: Send the full document

The simplest approach is to send the whole document to the server on every change.

doc.onChange(() => {
  // JSON is the easiest format because it's supported out of the box, but
  // you are free to implement your own serializer (e.g. HTML)
  const jsonDoc = doc.toJSON();
  // Choose the method you want to send the document to your server
  fetch("/save", { method: "POST", body: jsonDoc });
});

Pros

  • Very easy to implement
  • Useful baseline before adding incremental updates

Cons

  • Sends the entire document every time. The cost of data over the wire can be significant, especially if the document is large.
  • No concurrency handling (the server must decide which writer wins)

The root node ID is also the document ID. You can read it from the JSON as const docId = jsonDoc[0].

Strategy 2: Send operations (DIY)

Roll your own sync layer. The complexity is entirely up to you. A basic setup posts operations to the server, while an advanced one adds authentication, debouncing, retry policies, multi tab synchronization, version history, local storage, and other niceties.

The only requirement is that all clients must apply the operations in the same order. If a client connects and the server no longer holds the missing operations, the client must pull the current document state first, then start consuming live operations.

Pros

  • Efficient over the wire, especially for large documents
  • Robust to in‑flight saves: no dropped operations

Cons

  • The server returns the entire document on each request (this can be resolved)

DocNode Sync provides a batteries‑included, local‑first client/server that synchronizes documents in real time:

  • WebSockets for live sync
  • IndexedDB for local storage
  • Shared Worker for cross‑tab coordination

It can adapt strategy by context:

  • Single writer: send debounced operations and squash on the server only when needed (reads).
  • Multiple writers: send immediately and broadcast to all connected clients.