Building Realtime Collaborative Features: Lessons from Zed 1.0's Approach
How Zed 1.0's collaborative text editing inspired my approach to building a realtime workout dashboard on Fittrack, and why web standards still lag behind.
Zed 1.0 just shipped, and with it a polished realtime collaborative editing experience that feels almost magical. As someone who's been building a realtime dashboard for my fitness tracking app, Fittrack, I couldn't help but see parallels — and lessons I wish I'd known earlier.
The realtime problem
Realtime collaboration is hard. Every keystroke, every cursor move, every data update needs to sync instantly across clients without conflicts or lag. Zed's approach — a local-first architecture with CRDTs (Conflict-Free Replicated Data Types) — is elegant, but implementing it from scratch is daunting.
For my Fittrack dashboard, I needed to sync workout progress across devices. I initially naively used WebSockets with JSON patches. It worked for two users, but when I added session persistence and offline support, things got hairy.

Lessons from Zed's architecture
Zed's team open-sourced their CRDT library, which gave me a peek under the hood. Three things stood out:
- Operational transforms vs. CRDTs: Zed uses CRDTs for their automatic conflict resolution. I switched from manual OT to Yjs, a CRDT implementation, and conflict bugs dropped to zero.
- Serverless sync: Zed doesn't require a central server for realtime — they use a WebRTC-like peer-to-peer layer where possible. For Fittrack, I kept a simple server but made it stateless using Liveblocks as a managed storage layer.
- Undo across sessions: Zed supports undo even after reload. That required storing operations, not just state. I adopted a similar approach with an append-only log in IndexedDB.
Here's a snippet of how I integrated Yjs with my React frontend:
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
const doc = new Y.Doc()
const provider = new WebsocketProvider('wss://fittrack.example.com', 'workout-room', doc)
const yMap = doc.getMap('workoutData')
// Observe changes
yMap.observe(() => {
console.log('Data synced:', yMap.toJSON())
})
// Update with automatic conflict resolution
yMap.set('reps', newReps)
Applying it to Fittrack's dashboard
My Fittrack dashboard (repo: ketchalegend/fittrack) now shows realtime exercise progress — when one user completes a set, it instantly updates on all their devices. The key insight from Zed: treat the UI state as a pure function of a shared document.
I built a small abstraction layer on top of Yjs that maps database tables to Yjs maps. Every mutation goes through a central updateWorkout function that applies changes to the shared doc:
function updateWorkout(workoutId, patch) {
const doc = getDoc(workoutId)
doc.transact(() => {
const map = doc.getMap('workout')
for (const [key, value] of Object.entries(patch)) {
map.set(key, value)
}
})
}
This approach scales to multiple users because Yjs handles merging without explicit locking.
Mozilla's Prompt API and the standards gap
Mozilla recently opposed Chrome's Prompt API on their standards position, citing concerns about browser vendor lock-in. It reminded me that realtime collaboration still lacks a solid web standard — we rely on third-party libraries and WebSocket implementations that vary by browser.
Zed sidesteps this by building on a custom protocol over WebRTC. For a web app like Fittrack, I'm forced into WebSockets. The lack of a standard CRDT protocol means every library (Yjs, Automerge, etc.) has its own network layer.
Takeaway
Zed 1.0 proves that realtime collaboration can be buttery smooth when you invest in the right foundations. For my Fittrack project, switching to a CRDT-based approach (inspired by Zed's transparency) transformed a fragile sync system into something robust. If you're building any collaborative feature, skip manual OT and reach for a CRDT library from the start. Your future self — and your users — will thank you.