Hocuspocus 4: Real-Time Collaboration with Yjs CRDT — Complete Guide
Guide · June 4, 2026

Hocuspocus 4: Real-Time Collaboration
with Yjs CRDT — Complete Guide

Build real-time collaborative applications with Hocuspocus 4 and Yjs CRDT. From WebSocket server setup to production deployment — a practical guide with code examples for Node, Bun, Deno, and Cloudflare Workers.

Oleg Maximov June 4, 2026 15 min read

Introduction

Real-time collaboration is no longer a nice-to-have — it's expected. Google Docs, Notion, Figma, and Linear have set the bar: multiple users should be able to edit the same document simultaneously, see each other's cursors, and never lose data — even when the network drops.

Building this from scratch is notoriously hard. You need conflict resolution, operational transforms, state synchronization, presence awareness, and persistence. That's where Yjs and Hocuspocus come in.

Yjs is a CRDT (Conflict-Free Replicated Data Type) library that handles conflict resolution automatically. Hocuspocus is the WebSocket-based backend server that manages Yjs document synchronization across clients, with built-in persistence, authentication, and scaling.

Hocuspocus 4 was released in June 2026 and is the most significant update yet — adding multi-platform support (Node.js, Bun, Deno, Cloudflare Workers), a redesigned extension API, improved persistence, and significant performance improvements. Let's dive deep.

What Are CRDTs and Why Do They Matter?

Before diving into Hocuspocus, it's important to understand the technology underneath. CRDTs (Conflict-Free Replicated Data Types) are data structures that can be replicated across multiple users and merged automatically without conflicts — no central coordination required.

Unlike Operational Transformation (used by Google Docs), CRDTs have several key advantages:

Yjs implements the YATA algorithm, a type of CRDT optimized for text editing. It represents the document as a linked list of items, each with a unique identifier (client ID + clock). When two users insert text at the same position, Yjs orders the insertions deterministically by their identifiers — ensuring all clients converge to the same state.

// Yjs YATA algorithm — simplified concept
// Each item has: { id: [clientId, clock], content, origin }
// Two inserts at position 5 from different clients:
const itemA = { id: [1, 42], content: "Hello", origin: [null, 5] };
const itemB = { id: [2, 17], content: "World", origin: [null, 5] };

// Yjs orders by (clientId, clock) — itemB comes before itemA
// because clientId 2 < clientId 1 creates a deterministic ordering
// Integration: "WorldHello" — same on every client

What Is Hocuspocus?

Hocuspocus is the official server-side solution for Yjs. Think of it as the "backend for Yjs" — it handles:

Without Hocuspocus, you'd need to build all of this yourself on top of raw Yjs — which is possible, but time-consuming and error-prone. Hocuspocus packages it into a clean, configurable server with a plugin architecture.

What's New in Hocuspocus 4

Hocuspocus 4, released in early June 2026, is a ground-up rewrite with several major improvements:

Multi-Platform Support

The biggest headline: Hocuspocus 4 runs on Node.js, Bun, Deno, and Cloudflare Workers. The same API works across all platforms, with platform-specific adapters for differences in file I/O, WebSocket implementations, and storage backends.

Redesigned Extension API

The extension system has been overhauled. Instead of the old class-based hooks, Hocuspocus 4 uses a middleware-inspired pipeline where extensions register handlers for lifecycle events:

Improved Persistence

SQLite persistence now uses WAL mode by default, dramatically improving concurrent read/write performance. The new PostgreSQL adapter supports connection pooling and is suitable for multi-server deployments. The Redis adapter enables ephemeral document caching with optional persistence to disk.

Cloudflare Workers Integration

Hocuspocus 4 provides a first-class Cloudflare Workers adapter that uses Durable Objects for stateful WebSocket connections and DO storage for document persistence. This means you can run your collaboration infrastructure entirely at the edge with global low-latency access.

Performance Improvements

The new delta-sync protocol reduces bandwidth by 40-60% for typical editing sessions. Memory management has been rewritten to handle documents with thousands of concurrent editors more efficiently. The server startup time is roughly 3x faster than Hocuspocus 3.

Setting Up a Hocuspocus 4 Server

Let's build a minimal Hocuspocus 4 server. First, install the package:

npm install @hocuspocus/server @hocuspocus/extension-sqlite

Now create a basic server:

import { Server } from '@hocuspocus/server'
import { SQLiteExtension } from '@hocuspocus/extension-sqlite'

const server = Server.configure({
  port: 8080,

  // Persist documents to SQLite
  extensions: [
    new SQLiteExtension({
      database: 'collab.db',
      // WAL mode enabled by default in Hocuspocus 4
    }),
  ],

  // Authentication hook
  async beforeConnect({ connection }) {
    const token = connection.token
    
    if (!token || !validateToken(token)) {
      throw new Error('Authentication required')
    }
    
    const userData = decodeToken(token)
    return { user: userData }
  },
})

server.listen().then(() => {
  console.log('Hocuspocus 4 server running on port 8080')
})

That's it. With about 15 lines of server code, you have:

Client Integration: Connecting to Hocuspocus from the Browser

On the client side, you connect to the Hocuspocus server using the @hocuspocus/provider package:

npm install @hocuspocus/provider yjs
import * as Y from 'yjs'
import { HocuspocusProvider } from '@hocuspocus/provider'

// Create a Yjs document
const doc = new Y.Doc()

// Connect to Hocuspocus server
const provider = new HocuspocusProvider({
  url: 'ws://localhost:8080',
  name: 'my-document-id',  // unique document identifier
  doc,
  token: 'your-jwt-token',  // passed to beforeConnect hook
})

// The document is now synced with the server
// All changes are automatically broadcast to other clients

// Example: observe changes
const array = doc.getArray('my-list')
array.observe(event => {
  console.log('Document changed:', array.toArray())
})

// Make a change — it's automatically synced
array.push(['Hello from Client A!'])

The provider automatically handles reconnection, state synchronization, and conflict resolution. You can subscribe to connection status events:

provider.on('status', (event) => {
  switch (event.status) {
    case 'connected':
      console.log('Connected to Hocuspocus')
      break
    case 'disconnected':
      console.log('Disconnected — reconnecting...')
      break
    case 'connecting':
      console.log('Attempting to connect...')
      break
  }
})

Rich Text Editing with Yjs and ProseMirror

The most common use case for Yjs is collaborative rich text editing. The y-prosemirror binding connects Yjs documents to ProseMirror, one of the most powerful rich text editors in the JavaScript ecosystem:

npm install y-prosemirror prosemirror-state prosemirror-view prosemirror-model prosemirror-schema-basic prosemirror-example-setup
import { EditorState } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view'
import { schema } from 'prosemirror-schema-basic'
import { exampleSetup } from 'prosemirror-example-setup'
import { yDocPlugin, yCursorPlugin, yUndoPlugin } from 'y-prosemirror'
import * as Y from 'yjs'
import { HocuspocusProvider } from '@hocuspocus/provider'

const doc = new Y.Doc()
const provider = new HocuspocusProvider({
  url: 'ws://localhost:8080',
  name: 'document-id',
  doc,
})

// Get the Yjs type for ProseMirror
const yDocType = doc.get('prosemirror', Y.XmlFragment)

// Create the ProseMirror editor connected to Yjs
const state = EditorState.create({
  schema,
  plugins: [
    yDocPlugin(yDocType),    // bidirectional sync with Yjs
    yCursorPlugin(provider.awareness!),  // show other users' cursors
    yUndoPlugin(),            // shared undo history
    ...exampleSetup({ schema }),
  ],
})

const view = new EditorView(document.querySelector('#editor'), { state })

// Now every keystroke is synced in real-time
// Other users see your cursor position and edits live

The yCursorPlugin provides collaborative cursors and selections out of the box — users see each other's cursor positions, selections, and even user names, colors, and avatars.

Persistence Options in Depth

Hocuspocus 4 supports four persistence backends. Choosing the right one depends on your deployment model and scale requirements:

Backend Best For Scaling Performance
SQLite Single-server, prototyping, small teams Single instance Fast with WAL mode; ~10K docs on modest hardware
PostgreSQL Multi-server, production deployments Horizontal via connection pooling Good; write throughput limited by row locking
Redis High-throughput, ephemeral docs Cluster mode supported Excellent; in-memory speed
Cloudflare DO Edge deployments, global audiences Automatic (Durable Objects) Very good; data stays near users

PostgreSQL Persistence Example

import { Server } from '@hocuspocus/server'
import { PostgreSQL } from '@hocuspocus/extension-postgresql'

const server = Server.configure({
  port: 8080,
  extensions: [
    new PostgreSQL({
      connection: {
        host: 'localhost',
        port: 5432,
        database: 'collab',
        user: 'app',
        password: process.env.DB_PASSWORD,
      },
      // Auto-migrate schema on first run
      migrate: true,
      // Connection pool of 10 connections
      poolSize: 10,
    }),
  ],
})

server.listen()

Authentication and Authorization

Authentication in Hocuspocus 4 works through the extension pipeline. The beforeConnect hook fires before the WebSocket connection is established, allowing you to validate credentials and reject unauthorized clients:

import { Server } from '@hocuspocus/server'
import jwt from 'jsonwebtoken'

const server = Server.configure({
  // ...other config...
  
  async beforeConnect({ connection }) {
    // Extract JWT from the connection token
    const { token } = connection
    
    try {
      const decoded = jwt.verify(token, process.env.JWT_SECRET)
      
      // Return user context — available in all subsequent hooks
      return {
        user: {
          id: decoded.sub,
          name: decoded.name,
          role: decoded.role,
        },
      }
    } catch (error) {
      // Reject the connection
      throw new Error('Invalid or expired token')
    }
  },

  // Per-document authorization
  async onLoadDocument({ documentName, user }) {
    // Check if user has access to this document
    const hasAccess = await checkDocumentAccess(user.id, documentName)
    if (!hasAccess) {
      throw new Error('Access denied to this document')
    }
  },
})

For fine-grained permissions, you can implement per-document access control, read-only access for viewers, and role-based limitations on editing:

async onStoreDocument({ documentName, document, user }) {
  // Only admins can delete document history
  if (document.meta?.requestedDelete && user.role !== 'admin') {
    throw new Error('Only admins can delete documents')
  }

  // Log who saved what
  console.log(`User ${user.id} saved changes to ${documentName}`)
  
  // Optionally transform the document before saving
  // (e.g., sanitize HTML in rich text content)
  return document
}

Cloudflare Workers Deployment

Hocuspocus 4's Cloudflare Workers support is one of its most exciting features. You can deploy the entire collaboration backend to the edge, with documents stored in Durable Objects:

import { Server } from '@hocuspocus/server'
import { CloudflareDO } from '@hocuspocus/extension-cloudflare'

// This is a Durable Object that runs on Cloudflare's edge
export class HocuspocusDO {
  constructor(state, env) {
    this.server = Server.configure({
      extensions: [
        new CloudflareDO({
          state,
          // Durable Objects storage for persistence
          storage: state.storage,
        }),
      ],
    })
  }

  async fetch(request) {
    return await this.server.fetch(request)
  }
}

// wrangler.toml
// [durable_objects]
// bindings = [{ name = "HOCUSPOCUS", class_name = "HocuspocusDO" }]

This deploys to Cloudflare's global network — users connect to the nearest data center, and Durable Objects ensure state is consistent across requests. No servers to manage, no regions to configure.

Scaling Hocuspocus for Production

When your application grows beyond a single server, Hocuspocus 4 supports horizontal scaling through its Redis-based pub/sub layer:

import { Server } from '@hocuspocus/server'
import { RedisExtension } from '@hocuspocus/extension-redis'

const server = Server.configure({
  port: 8080,
  extensions: [
    new RedisExtension({
      // Redis pub/sub for cross-server sync
      publisher: { host: 'redis-cluster', port: 6379 },
      subscriber: { host: 'redis-cluster', port: 6379 },
    }),
    // Persistence on each server
    new PostgreSQL({ /* ... */ }),
  ],
})

// Deploy behind a load balancer
// All instances share document state via Redis pub/sub
// Each instance persists independently to PostgreSQL

With this setup, you can run multiple Hocuspocus instances behind a load balancer. When user A connects to instance 1 and user B connects to instance 2, Redis pub/sub ensures both receive each other's changes. PostgreSQL provides durable persistence that survives instance restarts.

Practical Patterns: Cursors, Awareness, and Presence

Beyond document sync, collaborative apps need awareness — knowing who's online, where their cursor is, and what they're doing. Yjs provides the Awareness protocol, and Hocuspocus relays it between clients:

// Client: update awareness state
provider.awareness.setLocalState({
  user: {
    name: 'Alice',
    color: '#ff6b6b',
    avatar: '/avatars/alice.png',
  },
  cursor: { x: 450, y: 120 },
  selection: { from: 23, to: 45 },
})

// Client: listen for other users' awareness
provider.awareness.on('change', ({ states }) => {
  states.forEach((state, clientId) => {
    if (clientId !== doc.clientID) {
      // Render other users' cursors and selections
      renderRemoteCursor(state.user, state.cursor)
    }
  })
})

This pattern enables features like:

Comparison: Hocuspocus vs Alternatives

Feature Hocuspocus 4 Liveblocks PartyKit ShareDB
Technology Yjs CRDT Proprietary CRDT Yjs CRDT OT (JSON0)
Self-Hosted Yes No (SaaS) Partially Yes
Platform Node, Bun, Deno, CF Workers Node (via SDK) PartyKit Cloud Node.js
Persistence SQLite, PostgreSQL, Redis, DO Managed SQLite, DO MongoDB, PostgreSQL
Offline Support Built-in (CRDT) Limited Built-in (CRDT) No
Rich Text ProseMirror, Quill, TipTap Built-in editor ProseMirror Quill (via plugin)
Pricing Free (MIT) From $599/mo From $49/mo Free (MIT)

Hocuspocus stands out for its open-source nature, multi-platform support, and flexible persistence. You own your infrastructure, your data never touches a third-party service, and you can deploy anywhere from a $5 VPS to Cloudflare's global network.

Real-World Use Cases

Hocuspocus and Yjs power collaborative features in production at scale:

Collaborative Document Editors

The classic use case. Multiple users edit the same document, see each other's cursors, and never lose work. Companies use it for internal wikis, proposal writing, code documentation, and meeting notes. With TipTap or ProseMirror as the editor, you get a full-featured rich text experience.

Whiteboard and Diagram Tools

Yjs isn't limited to text. With y-indexeddb for offline caching and custom Yjs types for shapes, connectors, and layers, teams can collaborate on diagrams, wireframes, and whiteboards in real time — similar to Figma or Excalidraw.

Code Editors (VS Code-like)

Using y-monaco (Yjs binding for Monaco Editor) or y-codemirror.next, you can add real-time collaborative editing to code editors. Teams use this for pair programming, code reviews, and classroom environments. Hocuspocus handles document persistence so code sessions survive server restarts.

Project Management Tools

Task boards, kanban boards, and databases benefit from Yjs's fine-grained synchronization. Each card, comment, and status change syncs in real time without page refreshes. Yjs's Y.Map and Y.Array types map naturally to document-oriented data models.

Migration from Hocuspocus 3

If you're upgrading from Hocuspocus 3, the migration path is straightforward but requires attention to a few breaking changes:

The Hocuspocus team provides a @hocuspocus/migration package that automates most of the migration. Test thoroughly on a staging environment before upgrading production.

Need real-time collaboration? See my development services

FAQ

What is Hocuspocus and how does it work with Yjs?
Hocuspocus is a WebSocket-based backend server for Yjs, a CRDT (Conflict-Free Replicated Data Type) library for building real-time collaborative applications. Hocuspocus manages Yjs document synchronization across multiple clients, handles persistence, authentication, and scaling — so you don't have to build the collaboration infrastructure from scratch. It's open-source (MIT) and self-hostable.
What's new in Hocuspocus 4?
Hocuspocus 4 brings multi-platform support (Node.js, Bun, Deno, and Cloudflare Workers), a redesigned extension API with middleware-inspired hooks, improved SQLite persistence with WAL mode and better indexing, a new Redis persistence adapter for horizontal scaling, built-in rate limiting, simplified authentication, and significant performance improvements — 40-60% less bandwidth usage and 3x faster server startup compared to Hocuspocus 3.
How do I set up a Hocuspocus 4 server?
Install via npm: npm install @hocuspocus/server @hocuspocus/extension-sqlite. Create a server with Server.configure(), add extensions for persistence and authentication, and call server.listen(). A minimal setup requires about 15 lines of code. Hocuspocus handles WebSocket connections, document sync, and conflict resolution automatically. It runs on Node.js, Bun, Deno, or Cloudflare Workers.
Can Hocuspocus 4 run on Cloudflare Workers?
Yes, Hocuspocus 4 is the first version with first-class Cloudflare Workers support. It leverages Durable Objects for stateful WebSocket connections and DO storage for document persistence. This lets you run collaboration infrastructure at the edge with global low-latency access and zero server management. Deploy via wrangler with the @hocuspocus/extension-cloudflare adapter.
What persistence options does Hocuspocus 4 support?
Hocuspocus 4 supports SQLite (file-based, best for single-server deployments with WAL mode), PostgreSQL (multi-server with connection pooling), Redis (in-memory, best for caching and ephemeral documents), and Cloudflare Durable Objects storage (edge-native). The persistence layer is pluggable — you can write custom adapters or chain multiple backends for tiered storage (e.g., Redis cache + PostgreSQL persistence).
How does Hocuspocus handle authentication?
Authentication uses the extension pipeline. The beforeConnect hook fires before the WebSocket connection is established — you validate JWT tokens, API keys, or any credential format. Return user context (id, role, permissions) which is available in subsequent hooks like onLoadDocument for per-document authorization. Invalid tokens reject the connection with an error.
Can I use Hocuspocus with React?
Yes. The Yjs ecosystem provides provider packages that connect React components to Hocuspocus. Use the @hocuspocus/provider package combined with Yjs document types. For rich text editing, pair it with y-prosemirror (React ProseMirror) or y-quill (React Quill). React components subscribe to Yjs document changes via Y.Doc observers and update automatically.

Build Real-Time Collaboration Today

Hocuspocus 4 makes real-time collaboration accessible to any project. Whether you're building the next Google Docs, a collaborative whiteboard, a pair programming tool, or a real-time project management app — the combination of Yjs CRDT and Hocuspocus gives you a production-ready foundation.

The best part? It's free, open-source, and self-hostable. You own your data and your infrastructure. No per-seat licensing, no vendor lock-in, no data leaving your servers.

If you're planning a project that needs real-time collaboration and want an experienced developer to architect and build it, let's talk. I've built collaborative applications with Yjs, Hocuspocus, WebSockets, and various frontend frameworks — I can help you choose the right architecture and avoid the common pitfalls.

Contact

Let's discuss your project

Need real-time collaboration for your app? I can help architect and build it. Tell me about your project — free initial consultation.