What Libraries Are Used for Real-Time Collaboration in Plane?
Plane relies on Yjs for CRDT document synchronization, @hocuspocus/provider and @hocuspocus/server for WebSocket transport, y-indexeddb for offline persistence, and @tiptap/extension-collaboration to bridge the ProseMirror editor with the shared document state.
The open-source project management platform Plane implements its real-time collaborative editing features through a specialized stack of libraries that handle conflict-free data replication and network transport. By examining the makeplane/plane source code, we can identify the specific libraries used for real-time collaboration in Plane and understand how they interact to provide seamless multi-user editing. This architecture enables concurrent document updates, automatic conflict resolution, and offline-first capabilities across distributed clients.
CRDT Engine: Yjs
At the foundation of Plane's collaborative system lies Yjs, a proven CRDT (Conflict-free Replicated Data Type) library that represents shared documents as Y-Doc instances. In packages/editor/src/core/helpers/yjs-utils.ts, the application initializes these documents to serve as the single source of truth for collaborative state.
All text edits, cursor positions, and document structural changes are applied to the Y-Doc, which automatically manages conflict resolution when simultaneous changes occur across multiple clients. The library's observation-based architecture ensures that local changes propagate efficiently while remote changes merge without data loss.
WebSocket Transport Layer
Client-Side Connection (@hocuspocus/provider)
For network communication, Plane utilizes @hocuspocus/provider on the client side to establish and maintain WebSocket connections with the backend. The implementation in packages/editor/src/core/hooks/use-yjs-setup.ts (lines 7-66) demonstrates how the provider wraps the Y-Doc and handles complex connection logic.
The provider manages authentication tokens, automatic reconnection strategies, and forced-close handling. When initialized, it synchronizes the local Y-Doc state with the remote server, ensuring that users immediately receive any updates that occurred while they were disconnected.
Server-Side Coordination (@hocuspocus/server)
The backend implementation resides in apps/live/src/hocuspocus.ts, where Plane runs @hocuspocus/server to manage WebSocket connections from multiple clients. This server receives document updates from connected clients, applies them to a shared Y-Doc instance, and broadcasts changes to all participants.
The server configuration supports optional extensions such as @hocuspocus/extension-redis for horizontal scaling across multiple server instances. This architecture allows Plane to handle high-concurrency scenarios while maintaining real-time synchronization guarantees.
Offline Persistence with IndexedDB
To support offline-first functionality, Plane integrates y-indexeddb for local document persistence. As referenced in packages/editor/src/core/hooks/use-yjs-setup.ts (lines 11-12), this library stores the Y-Doc state in the browser's IndexedDB storage.
When users reconnect after working offline, the IndexedDB persistence layer enables instant loading of the last known document state before WebSocket synchronization begins. This approach eliminates loading delays and allows editors to function without network connectivity.
Rich Text Editor Integration (@tiptap/extension-collaboration)
Plane connects its Tiptap-based editor to the collaborative infrastructure using @tiptap/extension-collaboration. The integration shown in packages/editor/src/core/hooks/use-collaborative-editor.ts (line 9) bridges the ProseMirror editor state with the Y-Doc synchronization layer.
This extension translates ProseMirror transactions into Yjs document updates and vice versa, enabling real-time collaborative rich-text editing. It handles complex formatting operations, cursor presence, and selection states while maintaining compatibility with Tiptap's existing extension ecosystem.
Implementation Examples
The following examples illustrate how these libraries interact in the Plane codebase:
Initializing the Collaborative Document
import { HocuspocusProvider } from "@hocuspocus/provider";
import * as Y from "yjs";
// Create a Y-Doc
const ydoc = new Y.Doc();
// Initialise the provider (WebSocket transport)
const provider = new HocuspocusProvider({
url: "wss://collab.plane.so", // Server URL
name: "my-document-id", // Shared document name
token: "jwt-auth-token", // Optional auth token
document: ydoc, // Pass the Y-Doc instance
onConnect: () => console.log("connected"),
onSynced: () => console.log("synced"),
});
Enabling Offline Storage
import { IndexeddbPersistence } from "y-indexeddb";
const persistence = new IndexeddbPersistence("my-document-id", ydoc);
persistence.on("synced", () => {
console.log("Local IndexedDB is now in sync with the remote document");
});
Configuring the Collaboration Server
import { Hocuspocus } from "@hocuspocus/server";
import { Redis } from "@hocuspocus/extension-redis";
const server = new Hocuspocus({
port: 3001,
extensions: [
new Redis({ host: "redis", port: 6379 }),
// Additional extensions (e.g., logger) can be added here
],
});
await server.listen();
console.log(`Hocuspocus server listening on ws://localhost:${server.port}`);
Connecting Tiptap to the Shared Document
import { Editor } from "@tiptap/react";
import Collaboration from "@tiptap/extension-collaboration";
const editor = new Editor({
extensions: [
Collaboration.configure({
document: ydoc, // The shared Y-Doc from above
}),
// …other extensions (starter-kit, mentions, etc.)
],
});
Summary
Plane's real-time collaboration stack combines several specialized libraries to deliver a robust editing experience:
- Yjs provides the foundational CRDT implementation in
packages/editor/src/core/helpers/yjs-utils.ts, handling automatic conflict resolution for concurrent edits. - @hocuspocus/provider manages WebSocket connections and reconnection logic on the client side within
packages/editor/src/core/hooks/use-yjs-setup.ts. - @hocuspocus/server powers the backend coordination in
apps/live/src/hocuspocus.ts, broadcasting changes to all connected clients. - y-indexeddb enables offline persistence by storing document state locally, as implemented in the setup hooks.
- @tiptap/extension-collaboration bridges the visual editor with the synchronization layer in
packages/editor/src/core/hooks/use-collaborative-editor.ts.
Frequently Asked Questions
What is the primary function of Yjs in Plane's architecture?
Yjs serves as the conflict-free replicated data type (CRDT) engine that represents collaborative documents as Y-Doc instances. According to the source code in packages/editor/src/core/helpers/yjs-utils.ts, it handles the core logic for merging simultaneous edits from multiple users without data loss or conflicts.
How does Plane maintain collaboration when users go offline?
Plane implements y-indexeddb to persist the Y-Doc state in the browser's IndexedDB storage. As shown in packages/editor/src/core/hooks/use-yjs-setup.ts, this allows the editor to restore the last known document state immediately upon reinitialization, enabling users to continue editing without an active network connection until synchronization resumes.
What distinguishes @hocuspocus/provider from @hocuspocus/server?
@hocuspocus/provider operates on the client side to manage WebSocket connections, authentication tokens, and reconnection logic, while @hocuspocus/server runs on the backend in apps/live/src/hocuspocus.ts to receive updates from multiple clients and broadcast changes. The provider initiates the connection; the server coordinates the shared document state across all connected instances.
How does Tiptap integrate with Plane's collaborative backend?
The @tiptap/extension-collaboration extension bridges the ProseMirror-based editor with the Yjs document layer. Implemented in packages/editor/src/core/hooks/use-collaborative-editor.ts, it translates editor transactions into Y-Doc updates and reflects remote changes back into the editor view, enabling real-time collaborative rich-text editing with cursor presence and selection synchronization.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →