Open-source project
ueberdosis/hocuspocus avatar
ueberdosis/hocuspocus

Hocuspocus: a WebSocket backend for Yjs documents

The Yjs CRDT WebSocket backend for conflict-free real-time collaboration in your app.

2,579 stars211 forksTypeScriptMIT

At a glance

What is it?
Hocuspocus is a self-hosted TypeScript server that speaks the Yjs sync protocol over WebSocket and persists documents through pluggable extensions. It is a good fit if you already build on Yjs and want to run the sync layer yourself; it is the wrong tool if you need an HTTP request/response API or a hosted service.
Who is it for?
Adopt Hocuspocus if your editor already stores state in a Y.Doc and you want the sync layer under your own control: the README's server example is a few lines and the SQLite extension is a single constructor argument.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem: Yjs needs a server that speaks its protocol

Yjs gives you a CRDT document that merges concurrent edits without a central arbiter. That solves the merge problem, not the transport problem. Two browsers editing the same Y.Doc still need somewhere to exchange updates, and someone has to decide what happens when the last client disconnects and the document exists only in memory. Hocuspocus is the second half of that pair. The README describes it as a plug and play collaboration backend based on Y.js, and the package is published as @hocuspocus/server. It is aimed at teams already committed to a Yjs-based editor: the repository topics list ProseMirror, Slate, and Tiptap, which are the editors whose bindings produce Y.Docs in the first place. If your editor state is not a Y.Doc, nothing here applies to you.

What the server actually does with a document

The mechanism is a persistent WebSocket connection per document room. Clients connect, the server holds the in-memory Y.Doc for that room, and updates flow between connected peers. The part that matters for production is the extension array. Extensions are constructed objects passed into the Server config, and they hook into the document lifecycle. The README's example wires exactly one: new SQLite({ database: 'db.sqlite' }) from @hocuspocus/extension-sqlite, which gives the server a place to write document state so a room is not lost when the process restarts. The onConnect hook in the same example is an async function, which tells you the lifecycle callbacks are awaited and can perform I/O before a connection is admitted. That is the seam where authentication would go. The README does not demonstrate authentication; it logs a crystal ball emoji. Treat the hook signatures as the real API surface and read the documentation site for the current list, because the README shows one hook out of what the package exposes.

Starting a server: the config keys in the README

The documented setup is short. Import Server from @hocuspocus/server and SQLite from @hocuspocus/extension-sqlite, then construct a Server with three keys: port set to 1234, an async onConnect function, and an extensions array containing the SQLite instance pointed at db.sqlite. Call server.listen() to start it. The README notes the default bind address is 127.0.0.1, with the WebSocket protocol prefixed on ws://127.0.0.1, so a deployment behind a reverse proxy or in a container will need that address and port handled explicitly rather than assumed. The SQLite extension is the only persistence option named in the README. The documentation site is where the other extensions and the full hook list would be described, and you should confirm the current set there rather than inferring it from this snippet. Note also that the example is presented as a setup you need to start a WebSocket server, not as a complete production configuration.

The stateful tier is the cost you are accepting

A WebSocket server that holds live Y.Docs in memory is a stateful service, and that shapes everything downstream: rolling deploys, horizontal scaling, and sticky routing all become your problem rather than the framework's. The README does not discuss scaling, clustering, or how two server instances would coordinate on the same document room. It also does not discuss what happens to in-flight edits if the process exits between the last SQLite write and the next one. Those are not criticisms of the design so much as consequences of it, and they are the questions to answer before you put this behind real users. The extension model is the intended answer: persistence, and presumably scaling, are meant to be added as extensions rather than solved in the core. Whether an extension for your datastore exists is something the README cannot tell you.

When a plain API is the better shape

The alternative depends on what you are actually building. If your application is a document editor with concurrent cursors, the closest comparison is not another CRDT server but an ordinary HTTP API backed by a database row and a last-write-wins update. That approach is simpler to operate: stateless handlers, no persistent connections, no in-memory document to reconcile, and no CRDT semantics to reason about in your data model. It fails in exactly the case Hocuspocus exists for, simultaneous edits to the same passage, where last-write-wins silently discards one person's work. So the decision is not which server is faster. It is whether your users edit the same content at the same time. If they do not, a REST endpoint plus optimistic UI is less machinery. If they do, you need a CRDT and you need something to sync it, and the README points at Tiptap Collab as the hosted version of that something for teams that do not want to run it themselves.

Licence, versions, and what maintenance looks like

Hocuspocus is MIT licensed, which permits commercial use and modification; the README points to the LICENSE.md file for the actual terms, and that file is what governs, not this summary. The release cadence visible in the repository is regular: v4.5.0, v4.6.0, and v4.7.0 all landed within roughly five weeks in 2026, with the most recent push to the main branch shortly after v4.7.0. Frequent minor releases on a 4.x line usually mean small additive changes rather than breaking ones, but the README does not state a compatibility policy, so pin your @hocuspocus/server version and read the release notes before upgrading across minors. The upgrade cost that matters is not the package itself but your extensions: anything you wrote against the lifecycle hooks has to keep matching the hook signatures, and the README's single onConnect example is not enough to tell you how stable those are. The project is funded partly through sponsorship and a paid cloud offering, which is worth knowing when you assess how much of the roadmap is driven by the hosted product.

Who should pick this up, and what to check first

The fit is narrow and clear: you have a Yjs document, you want the sync server on your own infrastructure, and you are willing to operate a stateful WebSocket tier. The README's example gets you to a listening server with SQLite persistence in about fifteen lines, and the extension array is a reasonable place to put the pieces the core leaves out. The misfit is equally clear: request/response applications, teams without the appetite for a persistent-connection service, and anyone whose editor does not already produce Y.Docs. The three things to verify before writing production code are the persistence extensions available beyond SQLite, the exact signature of the hooks you plan to use in your installed version, and how you will authenticate connections, because the README's onConnect hook logs an emoji and nothing more. Start by reading the hook list on the documentation site and confirming it matches the version you pin.

Editorial conclusion

Adopt Hocuspocus if your editor already stores state in a Y.Doc and you want the sync layer under your own control: the README's server example is a few lines and the SQLite extension is a single constructor argument. Do not adopt it if your collaboration model is request/response rather than a shared CRDT document, or if you would rather not operate a stateful WebSocket tier at all, in which case the README's pointer to Tiptap Collab is the alternative the maintainers themselves offer. Before committing, verify three things against the current docs: which persistence extensions exist beyond SQLite, whether the onConnect hook signature in your installed version matches the example, and how authentication is meant to be wired, since the README shows onConnect logging an emoji rather than checking a token.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. ueberdosis/hocuspocus on GitHub
Community notes

Community notes