Skip to Content
CollaborationCollaboration

Collaboration

StesuraEditor doesn’t depend on a transport. Every mount hook returns the same { editorState, dispatch, pluginFactory, schema }, so the backend is chosen by the hook, and the editor, plugins and UI extensions don’t change.

Choosing a backend

Pitter PatterLocal (offline)
Sync modelServer-authoritative OT (prosemirror-collab-commit)Same engine, authority in the browser
InfrastructureYour Postgres + Redis: a route in your app, or a standalone Node serverNone: IndexedDB + BroadcastChannel
Document storeYour database, as ProseMirror JSONBrowser IndexedDB
Who can co-editAny clientTabs of one browser
Presence / cursors
Commentscollab_thread table✅ IndexedDB (LocalCommentProvider)
Shared proofread cache✅ Redisin-memory only
Offline editing❌ needs the server
HookuseCollabEditoruseLocalCollabEditor
DocsPitter PatterLocal

For multi-user deployments, use Pitter Patter. The server is authoritative, and documents are stored as ProseMirror JSON in your own Postgres, where you can audit, query and back them up. We don’t use a CRDT: document editing rarely needs peer-to-peer merging, and bridging a CRDT to ProseMirror costs whole-document remote transactions (which break decorations), slow undo on long documents, and no marks on nodes or attributes on the doc node. See Why we’re moving away from Yjs .

Use Local when there is no server: local-first or desktop-style apps. Tabs co-edit in real time, and every confirmed keystroke is persisted.

The common shape

const { editorState, dispatch, pluginFactory, schema } = useCollabEditor({ ... }); // or useLocalCollabEditor({ ... }) / useLocalEditor({ ... }) <StesuraEditor state={editorState} dispatchTransaction={dispatch} schema={schema} pluginFactory={pluginFactory} nodeViews={stesuraNodeViews} uiExtensions={uiExtensions} />

On both backends:

  • Undo reverts only your own edits. prosemirror-history stays enabled: the collab plugin marks remote transactions so history skips them.
  • Comments go through a CommentAdapter, which each backend wires. See Comments.

Next steps

Last updated on