Realtime collaboration used to mean operational transforms, three weeks of debugging, and a paper from 1989 that you read twice and still didn't understand. CRDTs and good libraries have changed that. You can build a usable collaborative editor in an afternoon. Here's how.
What we'll build
- A document model backed by Yjs.
- Live cursors for everyone in the doc.
- Optimistic local edits with automatic conflict resolution.
- Persistence to a Postgres table via Lovable Cloud.
Step 1 — the data model
Yjs gives you a CRDT for free. Think of it as a JavaScript object that two browsers can edit at the same time and converge on the same final state.
tsimport * as Y from 'yjs'; const doc = new Y.Doc(); const text = doc.getText('content'); text.observe((event) => { console.log('text changed:', text.toString()); });
Step 2 — the transport
Two browsers need to exchange Yjs updates. The simplest transport is a WebSocket relay. We use a small server function that broadcasts updates to everyone subscribed to the same room id.
Step 3 — cursors
Yjs has an Awareness protocol: ephemeral state per user, broadcast alongside doc updates. Use it for cursor position, selection, name, and color.
tsxawareness.setLocalStateField('cursor', { anchor: editor.selection.anchor, head: editor.selection.head, user: { name: 'Iris', color: '#a78bfa' }, });
Step 4 — persistence
Every minute (or on disconnect) snapshot the Yjs state and write it to a Postgres jsonb column. On load, hydrate the doc from the snapshot before connecting to the relay. That's it. You now have a system where collaboration is live, history is durable, and the merge logic is provably correct.
What we left out
Comments, suggestions, version history, and presence avatars in the toolbar — all are layers on top of the same primitives. Once the awareness channel is open, every additional feature is a shape of data, not a new system.
Build it once and the next collaborative feature in your product takes an afternoon, not a quarter.
Iris Halvorsen
DX leadWorks on the parts of Luminax developers touch most: the editor, the previews, the moments between intent and result. Likes long-distance running and short, honest error messages.