Yjs: shared data types that turn a CRDT into something you can use from an editor
Shared data types for building collaborative software
At a glance
- What is it?
- A CRDT implementation that hands you Map and Array with automatic merge, offline editing and undo. The adoption list is the argument for it, and the license metadata is the first thing to check.
- Who is it for?
- Yjs is the right answer when several people edit the same data and you have decided against a server-side lock on every keystroke, because it hands you data types rather than a transport and leaves the network question to a provider. The adoption list is not decoration: Evernote, Gitbook, NextCloud, JupyterLab and Synthesia are all running on it, which is a better signal than any benchmark in the README.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Shared types rather than a CRDT API
The README's own framing is that Yjs is a CRDT framework with a powerful abstraction of shared data. Concretely it is a CRDT implementation that exposes its internal data structure as shared types, and those shared types are described as common data types like `Map` or `Array` with superpowers. Changes are automatically distributed to other peers and merged without merge conflicts.
That choice is the whole design. A CRDT library could have exposed operations, transactions and a document handle, and this one instead gives you the data structure and hides the merge machinery underneath. For an editor integration, that means binding to a shared type rather than implementing a text conflict resolver, which is the part of collaborative editing that projects consistently get wrong.
The capability list that follows is what the abstraction buys you. Network agnostic, explicitly p2p. Support for many existing rich text editors. Offline editing. Version snapshots. Undo and redo. Shared cursors. The README claims it scales well with an unlimited number of users and is well suited for even large documents, which is a claim from the project rather than a measurement, and the README separately links a third-party benchmark repository comparing Yjs against Automerge, which is where to look if you want numbers rather than adjectives.
Demos live in a separate repository at yjs/yjs-demos, and discussion happens on a discussion board at discuss.yjs.dev.
Who actually ships it, and the two adopters that use a different port
The README carries one of the longer adopter lists in this category, and it is the strongest argument for the library. Notables include AFFiNE, a local-first and privacy-first knowledge base; Cargo, a site builder; Gitbook; Evernote for note taking; Huly; NextCloud for content collaboration; JupyterLab for collaborative notebooks; AWS SageMaker for building machine learning models; linear for issues and roadmaps; Synthesia as a collaborative video editor; and Skiff as a private, decentralized workspace.
That range matters because the common objection to CRDTs is that they are a solution looking for a problem. Having both a note-taking app and a machine learning tool surface in the same list suggests the shared-types abstraction is portable across document-shaped and non-document-shaped data.
Two entries on that list need a caveat, and the README is careful enough to include it. Appflowy and Multi.app are both annotated as using Yrs rather than Yjs. Yrs is the Rust implementation of the same data structure, so those two are evidence for the design rather than for this particular JavaScript package. If your backend is Rust, that is the port to evaluate.
Some entries carry a star marker, and a few include their own descriptions, like Ellipsus supporting versioning, change attribution and blame, Serenity Notes offering end-to-end encrypted collaborative notes, and BlockSurvey offering end-to-end encryption for forms. The attribution angle is worth noticing because it points at a file in the repository called `attributing-content.md`, which is not something a library without opinions about authorship would bother to ship.
Repository layout: threat model, internals, renderer
The tree explains more about how the project is run than the README does. Alongside the usual `src/` and `tests/` directories there are four documents that tell you what the maintainers think the hard parts are: `THREAT_MODEL.md`, `SECURITY.md`, `INTERNALS.md`, and `attributing-content.md`. There is also `renderer.md`, which sits next to `test.html` and the `dist` output the build script produces.
A CRDT library shipping a threat model is unusual and worth taking seriously. The reason is structural: merging without conflicts means that whatever validation you skip is not caught by a conflict, because nothing ever conflicts. Two clients can disagree about a value, both merge cleanly, and the result is nonsense that no error reports. Documentation about attribution exists for a related reason, since a shared document loses any obvious mapping from characters to authors unless the application keeps one.
There is a `.well-known/` directory at the top level as well, which in that context suggests some form of published, machine-readable project metadata, and `funding.json` records the sponsorship target.
The build is TypeScript and ships ESM with hand-written type declarations. The package declares `type` as `module` and `sideEffects` as `false`, so a bundler can drop unused imports, and there is an `exports` map rather than a top-level `main` field alone, which is what lets the package expose a main entry, a `./meta` entry, and a `./testHelper` entry with types for each.
The package is named @y/y, not yjs
Here is the first thing to check before you write an install command. The project is called Yjs everywhere a human would look: the repository is yjs/yjs, the README headline is Yjs, the docs are at docs.yjs.dev, and the topics include `yjs`. But `package.json` names the package `@y/y` at version 14.0.0-rc.26, described as a Shared Editing Library.
Those two facts sit side by side and neither is wrong. The rename is recent and the release feed confirms the version line: v13.6.32 published on 2026-08-04, then v14.0.0-rc.25 on 2026-09-03, then v14.0.0-rc.26 on 2026-09-07, the same day as the last push. So the current published package is a release candidate of a major version, and a tutorial or an older blog post that tells you to install `yjs` is describing a world that has already moved on. Check the name and the version range in whatever lockfile you are about to commit.
The exports map, spelled out rather than abbreviated, shows how narrow the public surface is:
".": {
"types": "./dist/src/index.d.ts",
"default": "./src/index.js"
},
"./meta": {
"types": "./dist/src/utils/meta.d.ts",
"default": "./src/utils/meta.js"
},Only three entry points are published, plus `./package.json` itself. Everything else in `src/` is internal, so if you find yourself reaching past these entry points for a deep import, that is a signal you are depending on something unstable.
Testing by repetition rather than by assertion
The scripts in `package.json` describe an unusual testing philosophy. There is no assertion library and no snapshot suite in what is published. Instead there are two time-bounded runs:
"test": "NODE_ENV=development node ./tests/index.js --repetition-time 50",
"test-extensive": "node ./tests/index.js --production --repetition-time 10000",Both are `--repetition-time`, in milliseconds, and the extensive variant runs in `--production` mode for ten seconds per case. That is random-operation testing rather than a fixed list of scenarios: the harness generates sequences of edits against a document and checks that replicas converge, so a failure depends on finding a bad interleaving rather than on a test author having imagined it.
For a CRDT that is the right shape of test, because the space of interleavings is too large to enumerate. It also means failures can look irreproducible, which is worth knowing before you file one.
The debugging scripts follow the same logic. `gentesthtml` builds `test.html` by running the harness with `--include-dependencies @y/protocols`, which produces a single browser page for inspecting a failing case by hand. There are also `trace-deopt` and `trace-opt` targets using Node's deoptimization and optimization traces, plus a `debug` target that serves that page. If you are investigating a convergence bug rather than a feature, that generated HTML is the tool the project expects you to use.
Lint is chained in one command: markdownlint on the README, then `standard`, then `tsc`, then `dpdm` checking for circular imports and exiting non-zero on any cycle.
Support, licensing, and the limits of the claim
Two things about governance are worth knowing. The README offers a support contract through GitHub Sponsors, which funds weekly video calls with the maintainer, and it names Synergy Codes as a consultancy focused on real-time collaborative editing for visual apps, with interactive diagrams, graphs and data visualization as their specialty. That is a real answer to the question of who you call when a document will not converge, and it is a commercial relationship rather than a community one.
On licensing there is a discrepancy worth resolving yourself. The repository's license field reads NOASSERTION, meaning the platform could not classify it, while a LICENSE file is present in the tree and `attributing-content.md` sits alongside it. Read the LICENSE file. Do not infer the terms from the metadata field, and do not infer them from the sponsor links either.
The scope of the claim is also narrower than the README's first paragraph might suggest. Yjs merges concurrent edits. It does not know that a field should be a number, that two people deleted a row that other rows depend on, or that an editor is allowed to edit this part of the document at all. Access control, validation and authorization remain application work, and the threat model document exists precisely because that gap is real.
Against Automerge, the honest framing is that they are two implementations of the same idea with different tradeoffs in API surface and runtime, and the README points at a third-party benchmark repository rather than making the comparison itself. Against building the merge logic yourself, the case is not technical at all: the convergence tests above are a body of knowledge you would be recreating.
Editorial conclusion
Yjs is the right answer when several people edit the same data and you have decided against a server-side lock on every keystroke, because it hands you data types rather than a transport and leaves the network question to a provider. The adoption list is not decoration: Evernote, Gitbook, NextCloud, JupyterLab and Synthesia are all running on it, which is a better signal than any benchmark in the README. Two things to settle before you commit. First, the package in `package.json` is named `@y/y` at version 14.0.0-rc.26 while the project is called Yjs everywhere else, and the license field reads NOASSERTION even though a LICENSE file sits in the tree, so read that file rather than the metadata. Second, a CRDT merges rather than validates, which is why `THREAT_MODEL.md` and `attributing-content.md` exist; a document field is still your application's problem. Start with `docs.yjs.dev` and the demos repository, not with the source.
Frequently asked questions
What is Yjs used for?
It is a CRDT implementation that exposes its internal data structure as shared types, described as common data types like `Map` or `Array` with superpowers, where changes are distributed to other peers and merged without merge conflicts. It supports offline editing, version snapshots, undo and redo, shared cursors, and many existing rich text editors.
How do I install Yjs?
Check the name and version first, because the package in `package.json` is `@y/y` at version 14.0.0-rc.26 rather than `yjs`. The published package is ESM, declares `type` as `module` and `sideEffects` as `false`, and exposes only three entry points: the main entry, `./meta` and `./testHelper`. Version 13.6.32 was the last release before the 14.0.0 release candidate line.
Does Yjs need a server to synchronize users?
Not by itself. The README describes Yjs as network agnostic, explicitly p2p, which means it handles merging rather than transport, so something else has to carry updates between peers. It also works offline and merges later, so a server is optional in the sense that a peer-to-peer transport or a websocket provider can replace a central one.
What license is Yjs released under?
The repository's license metadata field reads NOASSERTION, which means the platform could not classify it, while a LICENSE file is present in the repository tree. The README points to GitHub Sponsors for a paid support contract, which is separate from licensing. Read the LICENSE file directly rather than relying on the metadata field.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/yjs-yjs)