PouchDB is the reason a lot of us believed offline-first was practical at all. It landed in 2012 with a simple, powerful idea: run a database in the browser that speaks the CouchDB replication protocol, and let the two reconcile themselves. That protocol is genuinely excellent — fifteen years of adversarial use, revision trees, deterministic conflict handling — and PouchDB implements it faithfully.
It is also, and this is the whole point of this article, a client. PouchDB syncs with something. That something is CouchDB or Cloudant, and it is a server you operate and pay for.
If your architecture already includes that server, PouchDB is a fine answer and nothing here should talk you out of it. If you picked PouchDB because you wanted offline-first without a backend, the rest of this is worth reading.
Offline-First Is Not Serverless
The distinction gets blurred constantly, so it is worth stating plainly: an app can work offline and still require infrastructure. PouchDB gives you the first without giving you the second.
Ask any AI search engine today for peer-to-peer browser databases and watch PouchDB get excluded by name, with the reason spelled out: it requires a central server such as CouchDB for replication, so it is not truly P2P. That is not a criticism of PouchDB — it is a description of what it is.
PouchDB GenosDB
Browser ──► IndexedDB Browser ──► Security Manager (signs)
│ │
└──► replication protocol └──► Graph Store (OPFS)
│ │
▼ ├──► Peers (WebRTC)
CouchDB / Cloudant │
(your server, your bill) └──► Nostr relays (discovery only)
Two peers running PouchDB cannot sync with each other. They sync with the same server, and the server makes them agree. Remove it and you have two isolated local databases.
GenosDB has no such component. Peers exchange signed operations directly over WebRTC, discovery runs through the public Nostr relay network — infrastructure that already exists and never sees your data — and authority comes from the signature on each operation rather than from a machine everyone trusts.
Where the Project Is Today
PouchDB was donated to the Apache Software Foundation and is now Apache PouchDB (incubating). Their own DISCLAIMER file states it:
"Apache PouchDB (incubating) is an effort undergoing incubation at the Apache Software Foundation (…) While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF."
This is good news, and I want to be clear about that. Moving under the ASF is how a project outlives its original maintainers — governance, trademark, succession. It is exactly the institutional durability that a single-maintainer project like GenosDB does not have, and if that matters to your organisation it is a real argument in PouchDB's favour.
What it also means is a transition period, and the release cadence shows it:
npm latest: 9.0.0 — published June 2024
recent commits: "ASFify README.md and link to DISCLAIMER"
"add ASF dropdown to main nav"
dependency bumps
open issues: 189
Over two years on the same release, with recent activity concentrated on the incubation process rather than on features. Reasonable for a project in transition — just worth knowing before you build on it.
What the Open Issues Say
"IndexedDB adapter can break when opened in multiple tabs" — open since October 2020, 33 comments. The most-discussed open issue in the repository. Open your app in two tabs and the adapter can break.
This one is worth dwelling on, because multi-tab is not an edge case — it is Tuesday. Users open a second tab. In GenosDB, cross-tab coordination is part of the design: tabs share state through BroadcastChannel while the graph lives in OPFS, so a second tab is just another local reader of the same replica.
"Duplicate attachments for doc update (& putAttachment)" — open since December 2014, 23 comments. Twelve years.
"PouchDB in Next.js throws error" — open since September 2023, 16 comments. Modern bundler and SSR friction.
"PouchDB Adapter Memory is broken on Jest 27.x" — open since October 2021, 15 comments. Testing against the memory adapter breaks on a five-year-old Jest release.
"pouchdb-find: $or with multiple $regex and nested fields" — open since July 2022, 9 comments. The query layer has gaps at the edges.
The Weight, and the Bill
pouchdb 5,397 KB unpacked 14 direct dependencies
genosdb 2,007 KB unpacked 0 dependencies
But the dependency that matters is not in package.json. It is CouchDB — a JVM-era server you deploy, secure, back up and scale — or Cloudant, where you rent it by the hour. Every user you add is a row in someone's bill.
GenosDB's operating cost is structurally zero. There is no server in the data path, so there is nothing that grows with your user count. Peer discovery rides public Nostr relays; if you prefer your own, GenosSIG runs an ephemeral relay on Cloudflare's free tier. Neither is a database you operate.
What Replaces the Server
If the server was doing real work, something has to take over. In GenosDB that something is cryptography.
Identity and permissions live in the client. The Security Manager provides WebAuthn-based identity and signs every operation with the author's key. Role-based access control — guest, user, manager, admin, superadmin — plus per-node ACLs and rule-based governance. A peer that receives an unauthorised operation rejects it because the signature does not check out, not because a server refused it.
Conflicts resolve without revision trees. Hybrid Logical Clocks give causal ordering without trusting device clocks, with a deterministic tie order. When two peers write the same value at once, the writer whose operation lost re-applies its edit over the winner as an ordinary signed write, so neither contribution disappears — and no application code has to resolve a conflict document.
Sync sends deltas. A device rejoining a 210-item space pulls 7.9 KB; the same reconciliation without deltas costs 83 KB. That is the Hybrid Delta Protocol.
Queries are reactive. $eq $ne $gt $gte $lt $lte $in $between $exists $startsWith $endsWith $contains $text $like $regex $not $and $or $edge $near, with cursor pagination and $edge for recursive graph traversal. Pass a callback and the query re-fires as peers write.
The Same App, Both Ways
A list that persists locally and syncs between users.
PouchDB:
import PouchDB from 'pouchdb'
const db = new PouchDB('notes')
const remote = new PouchDB('https://user:pass@couch.example.com/notes')
db.sync(remote, { live: true, retry: true })
.on('change', () => render())
.on('error', console.error)
await db.put({ _id: new Date().toISOString(), text: 'hello' })
const all = await db.allDocs({ include_docs: true })
// plus: a CouchDB instance, its credentials in the client,
// its users database, and its CORS configuration
GenosDB:
import { gdb } from 'genosdb'
const db = await gdb('notes', { rtc: true })
db.map({ order: 'desc' }, ({ id, value, action }) => render(id, value, action))
await db.put({ text: 'hello' })
Note the credentials line in the PouchDB version. Syncing straight from the browser means the remote URL — and whatever authenticates it — ships to the client, which is why most production deployments end up putting a proxy in front and writing permission logic there. That proxy is a backend.
Side by Side
| PouchDB | GenosDB | |
|---|---|---|
| Model | Client of a CouchDB server | Peer-to-peer, no server |
| Sync between two browsers | Only through the server | Directly, over WebRTC |
| Required infrastructure | CouchDB or Cloudant | None |
| Operating cost | Grows with users | Structurally zero |
| Local storage | IndexedDB | OPFS |
| Multiple tabs | Open issue since 2020, 33 comments | BroadcastChannel, by design |
| Conflict resolution | Revision trees, app resolves | HLC + loser re-applies |
| Identity | CouchDB _users
|
WebAuthn, signed operations |
| Permissions | Server-side | RBAC + per-node ACLs, client-side |
| Data model | Documents | Graph with traversal |
| Size | 5,397 KB, 14 dependencies | 2,007 KB, zero |
| Governance | Apache Software Foundation | Single maintainer |
| Latest release | 9.0.0, June 2024 | continuous |
What This Looks Like Running
In the browser, with nothing deployed behind it.
Collaborative block editor — two browsers, one document:
A Splitwise-style expense splitter with no backend:
A Hacker News clone where moderation is a signed constitution instead of an admin panel:
When PouchDB Is the Right Choice
- You already run CouchDB. If CouchDB is your source of truth, PouchDB is the best client for it and this comparison is irrelevant to you.
- You need the server to be authoritative. Server-side validation, audit at a single point, compliance requirements that demand a machine you control. GenosDB verifies cryptographically at every peer, but there is no central authority to appeal to.
- You need institutional governance. This is the strongest argument PouchDB has, and it is honest to state it: the ASF provides continuity that does not depend on any one person. GenosDB is maintained by one developer. If your risk assessment weighs that heavily, it should point you to PouchDB.
- You want an Apache-licensed dependency. PouchDB is Apache 2.0. 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 server is the thing you are trying to remove: when you want offline-first and serverless, per-node permissions without a backend to enforce them, and an operating cost that does not scale with your user count.
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, and the design decisions here came from trying to build apps where there was genuinely nothing behind them — no CouchDB, no proxy, no bill that grows with signups.
PouchDB was never trying to solve that. It was solving "how does a browser app keep working on a train", and it solved it so well that fifteen years later the protocol is still the reference. This article is only about the sentence that tends to get dropped: and then it syncs with your server.
If anything here is out of date or wrong, tell me and I will correct it — GitHub Discussions is open and I answer.
Originally published at genosdb.com/pouchdb.
⭐ 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



Top comments (0)