Automerge vs GenosDB: The Price of Keeping Every Version
Automerge keeps the full history of every change — a real capability with a real invoice: memory, a 45 MB WebAssembly package, and a sync layer that has never left alpha.

Full Stack Developer - dWEB R&D
Automerge is the most intellectually ambitious CRDT in JavaScript. It comes out of the Ink & Switch research on local-first software, its core is written in Rust and compiled to WebAssembly, and it does something the others do not: it keeps the entire history of every change, so you can rewind a document, inspect who wrote what, and merge branches of data the way you merge branches of code.
That is a genuine capability, and when you need it there is no substitute. But it is not free, and the invoice arrives in three places: memory, bundle weight, and the maturity of the layer you need to actually sync anything.
This article is about that invoice. If you want the argument about how convergence can work without a CRDT at all, that is a separate piece: real-time collaboration without a CRDT library. And if you are weighing Automerge against Yjs specifically, that comparison is here.
What Automerge Keeps
Every CRDT stores metadata beyond your data. Automerge stores more than most, on purpose: a full operation history, per-actor, that survives compaction and travels with the document. That is what makes getChanges, time travel and attribution possible.
The consequence is that a document is never just its current state. It is its current state plus every state it has ever been in, and both live in memory while you work.
The Invoice, Item by Item
Memory
These are all open issues in the Automerge repository:
| Issue | Filed | Signal |
|---|---|---|
Memory leak with initSyncState |
Apr 2024 | 9 reactions, zero comments |
| High memory spike on load and save, sometimes causing OOM | Aug 2023 | 8 comments |
| Unexpected quadratic performance loading a collaborative document | Apr 2024 | 3 comments |
| Degrading performance over time | Jul 2024 | open |
| Save and Load performance | May 2023 | 6 comments |
| Performance regression on main | Sep 2025 | 7 comments |
Tiny ReceiveSyncMessage is slow |
May 2025 | open |
Seven open issues about memory and speed, and the most-reacted of them — a memory leak in the sync-state initialiser — has been sitting since April 2024 without a single reply. There is also an open request from November 2025 titled "Consider publishing new benchmarks", which tells you something about how hard this is to measure from outside.
The WebAssembly tax
The Rust core has to reach the browser somehow, and that path is where a lot of developer time goes:
| Issue | Filed | Comments |
|---|---|---|
| The WebAssembly module seems to be missing from the package | Dec 2023 | 17 |
| Bundling with Parcel | Feb 2023 | 11 |
wasm.__wbindgen_add_to_stack_pointer is not a function |
Oct 2023 | 6 |
Deno: automerge_wasm_bg.wasm is not vendored |
Mar 2023 | 5 |
| Running Automerge in a Service Worker | Oct 2023 | 4 |
decodeChange() panics (WASM capacity_overflow) |
Apr 2026 | open |
Panic after migrate_actors unwrap |
Oct 2025 | open |
Every bundler needs its own WASM incantation, and when the Rust side fails it fails as a panic — a capacity_overflow or an unwrap, surfacing in your browser console with no JavaScript stack to follow.
The package itself:
@automerge/automerge 45,455 KB unpacked
genosdb 2,007 KB unpacked, zero dependencies
The sync layer is still alpha
Automerge merges documents; it does not move them between devices. For that there is automerge-repo, the official networking and storage layer. Its current state:
npm latest: 2.6.0-alpha.3
open issues: 97
other dist-tags: next, authors, subduction
The library you need in order to actually build a collaborative app has never shipped a stable release. That is not a hidden fact — the version number says it plainly — but it is easy to miss when you are evaluating Automerge itself, which is at a confident 3.4.1.
What GenosDB Does Instead
GenosDB also keeps an operation log — but for a different purpose, and with a different lifetime.
The oplog exists so a reconnecting device can receive only what it missed rather than a full state transfer: rejoining a 210-item space costs 7.9 KB, where the same reconciliation without deltas costs 83 KB. It is a synchronisation mechanism, described in the Hybrid Delta Protocol. What it is not is a permanent per-actor archive that has to be resident in memory for the document to be usable.
The trade is explicit: you give up time travel, and you stop paying for it.
Everything else is JavaScript, with no WebAssembly anywhere:
import { gdb } from 'genosdb'
const db = await gdb('my-room', { rtc: true })
No bundler configuration, no .wasm asset to vendor, no panics from a Rust layer — and no separate repo package in alpha, because persistence (OPFS), transport (WebRTC via GenosRTC) and peer discovery (public Nostr relays, no signaling server of your own) are in the same two-megabyte package.
And convergence still happens. Concurrent writes to the same value are reconciled by Hybrid Logical Clocks with a deterministic tie order, and the writer whose operation lost the race re-applies its edit over the winner as an ordinary signed write, so neither contribution is dropped.
What Arrives in the Same Package
Automerge, like Yjs, has no opinion about who you are or what you may do — that is outside its scope. GenosDB puts it inside the database:
- Identity, via WebAuthn or a mnemonic, with every operation signed by its author.
- Permissions: RBAC with guest/user/manager/admin/superadmin, per-node ACLs, and rule-based governance. Enforced by signature at every peer, with no trusted server.
- Queries, reactive:
\(eq \)gt \(in \)between \(text \)like \(regex \)and \(or \)edge $near, with cursor pagination and recursive graph traversal. - Encryption, per record, where each record carries its own wrapped key — a read costs 1.2 ms, against roughly 10.9 ms for the conventional PBKDF2-per-record approach.
The Same App, Both Ways
Automerge — document plus repo plus storage plus network adapter:
import { Repo } from '@automerge/automerge-repo' // latest: 2.6.0-alpha.3
import { IndexedDBStorageAdapter } from '@automerge/automerge-repo-storage-indexeddb'
import { BrowserWebSocketClientAdapter } from '@automerge/automerge-repo-network-websocket'
const repo = new Repo({
storage: new IndexedDBStorageAdapter(),
network: [new BrowserWebSocketClientAdapter('wss://your-sync-server.example')]
})
const handle = repo.create()
handle.change(doc => { doc.blocks = [{ text: 'hello' }] })
handle.on('change', ({ doc }) => render(doc.blocks))
// plus: a WASM asset your bundler has to emit correctly
// plus: identity and permissions, which are yours to build
GenosDB:
import { gdb } from 'genosdb'
const db = await gdb('my-room', { rtc: true })
db.map({ order: 'desc' }, ({ id, value, action }) => render(id, value, action))
await db.put({ text: 'hello' })
Side by Side
| Automerge | GenosDB | |
|---|---|---|
| Core | Rust compiled to WebAssembly | JavaScript, no WASM |
| Package size | 45,455 KB unpacked | 2,007 KB, zero dependencies |
| History | Full, permanent, in memory | Oplog for delta sync only |
| Time travel | Yes — a real strength | No |
| Sync layer | automerge-repo, alpha, 97 open issues |
Built in, stable |
| Storage | Separate adapter package | OPFS, native |
| Network | Separate adapter + your server | WebRTC + public Nostr relays |
| Identity | None | WebAuthn / mnemonic, signed ops |
| Permissions | None | RBAC + per-node ACLs + governance |
| Queries | Walk the document in JS | Full operator set, reactive |
| Failure mode | Rust panic in the console | JavaScript exception |
What This Looks Like Running
In the browser, with nothing deployed behind it.
Collaborative block editor — two browsers, one document:

dCode — branches, commits and pull requests, peer-to-peer:

A Hacker News clone where moderation is a signed constitution instead of an admin panel:

When Automerge Is the Right Choice
Be honest with yourself about one question: do you need the history, or do you just need the merge?
- You need time travel or attribution. Rewinding a document, showing who changed what, branching and merging data like code — Automerge does this and GenosDB does not. If that is the product, the memory cost is the price of the feature and it is worth paying.
- You are doing research on local-first software. Automerge is where that work happens, and the Ink & Switch material around it is the best writing on the subject.
- Rich text with full editing history. The combination of a mature text CRDT and a permanent history is genuinely rare.
- You want an open-source dependency. Automerge is MIT. GenosDB's bundle is free for personal and commercial use, but the source is proprietary by deliberate governance choice — it is not open source, and describing it as such would be inaccurate.
GenosDB is the better fit when the history is not the product: when you want the live collaboration, plus identity, permissions, relations and queries, in one dependency-free package that no bundler has to be taught about.
A Note on Where This Comes From
I have spent years building browser P2P databases — I wrote the official GUN documentation platform and contributed to that codebase before starting GenosDB. The decision not to keep a permanent operation history was one of the earliest and least comfortable ones, because history is genuinely useful. It was made after watching what it costs in memory on a device that is not a laptop.
Automerge chose the other side of that trade deliberately, and for the problems it targets it chose correctly. This article is only about making the trade visible before you inherit it.
If anything here is out of date or wrong, tell me and I will correct it — GitHub Discussions is open and I answer.
⭐ Found this useful? Star GenosDB on GitHub — or spin it up in seconds: npm i genosdb.
This article is part of the official documentation of GenosDB (GDB). GenosDB is a distributed, modular, peer-to-peer graph database built with a Zero-Trust Security Model, created by Esteban Fuster Pozzi (estebanrfp).
📄 Whitepaper | overview of GenosDB design and architecture
🛠 Roadmap | planned features and future updates
💡 Examples | code snippets and usage demos
📖 Documentation | full reference guide
🔍 API Reference | detailed API methods
💬 GitHub Discussions | community questions and feedback
🗂 Repository | Minified production-ready files
📦 Install via npm | quick setup instructions



