Local-first data

What are Automerge and Yjs?

Automerge and Yjs are open-source CRDT libraries for building collaborative and local-first apps. Automerge stores data as a JSON-like document that carries its full change history, with a Rust core exposed to JavaScript and C. Yjs exposes CRDTs as shared types such as Y.Map, Y.Array and Y.Text, with separate providers for networking and storage. Both are MIT licensed.

Learning objectives

After reading this article you will be able to:

  • Describe what Automerge and Yjs share as network-agnostic CRDT libraries
  • Compare Automerge and Yjs on data model, history and networking
  • Choose between Automerge and Yjs using editor, history, language and transport needs

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-repo package.

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.Doc holds named shared types: Y.Map, Y.Array, Y.Text, and Y.XmlFragment and Y.XmlElement for 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-websocket for a client and server, y-webrtc for peer-to-peer sync over WebRTC, and y-indexeddb for 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-crdt project with bindings for Python, Swift, Kotlin and others.

How they differ

AutomergeYjs
Data modelJSON-like document with nested maps, lists, text and countersDocument of shared types: map, array, text and XML
HistoryFull change history, with versions, branches and mergesGarbage collection of deleted content can be turned off to restore old content
Sequence algorithmRGA for lists, Peritext for textAdaptation of YATA
Networking and storageSeparate libraries, collected in automerge-repoProviders for WebSocket, WebRTC, IndexedDB and more
Core implementationRust, with JavaScript (WebAssembly) and C interfacesJavaScript, with compatible ports such as y-crdt in Rust
LicenseMITMIT (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.

Frequently asked questions

Do Automerge and Yjs need a server?

No. Both merge changes on each device and leave the network to separate packages. Both can sync through a server or directly between peers, and Automerge's documentation adds that a document can even travel as a file. A server can still help relay updates between devices that are rarely online at the same time.

Sources

Build it with Offline Protocol

The DataStore reference describes the replicated documents built into the Offline Protocol Mesh SDK, with map, list, text and counter collections, document lifecycle and the events an app listens to.

Read the DataStore reference