Real-time collaboration
Edit pages together with live cursors, powered by Hocuspocus and Yjs.
Pages can be edited by several people at once, with live cursors and conflict-free merging.
How it works
Collaboration runs as a dedicated Node service (apps/collab) built on
Hocuspocus and Yjs. The editor
in the web app connects to it over WebSocket; edits are exchanged as CRDT
updates, which merge deterministically without a central lock — so two people
typing in the same paragraph never clobber each other, and offline edits reconcile
when the connection returns.
Browser (TipTap editor) ──ws──▶ apps/collab (Hocuspocus)
│ │
│ ▼
│ yjs_state column (PostgreSQL)
▼
shared TipTap schema ◀── same schema used on both endsShared schema
The editor and the collab service share one TipTap schema. Because both ends agree on the document shape, the Yjs document and the rendered content stay consistent, and the extracted text (used for search and internal links) is derived from the same source.
Persistence
The collaborative document state is stored in a yjs_state column on the
page. The service loads it on connect and persists updates, so a page's live state
survives restarts.
Authentication
Connections are authorized with a page-scoped, signed token. The web app
requests a collab token for a specific page (pages.collabToken), and the collab
service verifies it with the same BETTER_AUTH_SECRET the API uses — which is
why the collab service must share that secret.
In a self-hosted deployment the collab service listens on port 1234 and the browser reaches it
via VITE_COLLAB_URL (ws:// locally, wss:// in production). See
Configuration.