What they have in common
Automerge and Yjs are libraries, not services. Each gives an app a CRDT data structure that every device keeps a full copy of. People edit their own copy, even offline, and when copies exchange changes the library merges them automatically, so every device ends up with the same content without a server deciding the result.
Both projects describe themselves as network agnostic. Automerge’s documentation says it works over any connection-oriented protocol, client and server or peer-to-peer, and even over one-way channels such as a file sent by email. The Yjs README calls it network agnostic and peer-to-peer capable, and its documentation says clients sync up once they have received all document updates, in whatever order. Neither library moves bytes on its own; separate packages connect it to a network or to storage.
Both are open source under the MIT License. For Automerge, GitHub reports the license as MIT. For Yjs, GitHub’s API does not identify the license, but the repository’s LICENSE file is the MIT License and the README describes Yjs as MIT licensed.
Automerge
Automerge describes itself as a library of data structures for building collaborative applications, designed for local-first software. It came out of Ink & Switch, whose local-first essay says it is based on their earlier research on JSON CRDTs.
- Data model. A document is a root map from strings to values. Values can be nested maps, lists, text, counters, timestamps, byte arrays and other simple types. Lists use an RGA sequence and text uses the Peritext CRDT, which also supports formatting marks.
- History. The documentation compares Automerge to Git. It keeps track of every change, so an app can view old versions, compare them, create branches and choose when to merge them.
- Concurrent writes. If two devices set the same property at the same time, Automerge picks one value as the winner on every device and keeps the others, which an app can read with
getConflicts. The winner is chosen by operation ID, a counter plus the ID of the actor that made the change, not by wall-clock time. - Implementation. The core is written in Rust, compiled to WebAssembly for JavaScript, and exposed through a C library. Bindings to particular networks live in separate libraries, collected in the
automerge-repopackage.
Yjs
Yjs describes itself as a CRDT implementation that exposes its internal data structure as shared types. These are data types that look like ordinary maps and arrays but sync and merge automatically.
- Data model. A
Y.Docholds named shared types:Y.Map,Y.Array,Y.Text, andY.XmlFragmentandY.XmlElementfor structured documents. Shared types can be nested and observed for changes. - Updates. Changes are encoded as compact binary document updates. The documentation states that updates are commutative, associative and idempotent, so they can be applied in any order and more than once. A state vector lets two clients exchange only what the other is missing.
- Providers. Networking and storage live in separate modules called providers. The README lists
y-websocketfor a client and server,y-webrtcfor peer-to-peer sync over WebRTC, andy-indexeddbfor storing updates in the browser, and providers can be combined. - Editors and ports. The README lists bindings for text editors including ProseMirror, Quill, CodeMirror and Monaco. Its algorithm is a modified version of the YATA CRDT. Compatible ports exist in other languages, such as the Rust
y-crdtproject with bindings for Python, Swift, Kotlin and others.
How they differ
| Automerge | Yjs | |
|---|---|---|
| Data model | JSON-like document with nested maps, lists, text and counters | Document of shared types: map, array, text and XML |
| History | Full change history, with versions, branches and merges | Garbage collection of deleted content can be turned off to restore old content |
| Sequence algorithm | RGA for lists, Peritext for text | Adaptation of YATA |
| Networking and storage | Separate libraries, collected in automerge-repo | Providers for WebSocket, WebRTC, IndexedDB and more |
| Core implementation | Rust, with JavaScript (WebAssembly) and C interfaces | JavaScript, with compatible ports such as y-crdt in Rust |
| License | MIT | MIT (LICENSE file) |
How to choose
Neither library is a complete sync system on its own. Each handles merging and leaves transport and storage to separate packages. The Ink & Switch essay makes the same point about CRDTs in general: they merge data but say nothing about how edits reach each device. With that in mind, a few questions narrow the choice:
- Is the app built around a text editor? Yjs lists ready-made bindings for several editors. Automerge has its own rich text type, and its cookbook covers ProseMirror.
- Do people need to see and compare history? Automerge keeps every change by design and treats branching and merging as part of the model.
- Which language runs on the device? Automerge’s core is Rust, with JavaScript and C interfaces. Yjs itself is a JavaScript library, with ports to other languages through
y-crdt. - What transport do you have? Both work over WebSockets and WebRTC. For devices that meet over Bluetooth or a local mesh, check whether an adapter or provider exists, or plan to carry the updates yourself; the replicated document article covers what has to travel.
Whichever you pick, the merge rules still decide what happens when two people change the same thing. The merging article explains why every copy ends up the same.