How CouchDB’s MVCC Conflict Resolution Works – A Practical Engineer’s Guide
CouchDB’s MVCC keeps every write as a leaf revision, so concurrent updates create conflicts that the application must resolve. Learn how to detect, merge, and clean up these conflicts to avoid storage bloat and data divergence.
18 Sept 2026, 01:53 UTC

Problem: Concurrent Updates in a Distributed Environment
When two or more clients write the same document at the same time on different CouchDB nodes, the database cannot simply overwrite the old value. CouchDB uses Multi‑Version Concurrency Control (MVCC) to keep every write as a distinct leaf in the revision tree. The result is a set of conflicting revisions that both survive the write, which can surprise developers who expect a single “latest” value.
Thesis: You Must Resolve, Not Ignore
In CouchDB the application is responsible for choosing a winning revision, merging data if necessary, and cleaning up the losers. Failure to do so leads to unbounded disk growth and silent data divergence across replicas.
1. MVCC in CouchDB – What the Database Stores
- Revisions are identified by a _rev token (e.g.,
1-abc123,2-def456). Each update creates a new leaf. - Concurrent updates to the same
_revproduce multiple leaves that share the same parent. - The full revision tree is stored in the database file, but only the leaf revisions are exposed via the API.
2. Seeing the Conflict – Querying and Monitoring
To inspect a conflict you request the document with the ?conflicts=true flag. The response includes a conflicts array listing the _rev values of the divergent leaves.
curl -X GET http://localhost:5984/mydb/notes/123?conflicts=true
Alternatively, the _changes feed with style=all_docs streams every leaf, including conflicts, which is useful for real‑time monitoring.
curl -N http://localhost:5984/mydb/_changes?feed=continuous&style=all_docs
3. Conflict Resolution Patterns
- Choose the Winning Revision
Decide which _rev should survive. This could be the newest based on a timestamp, the one with the highest revision number, or a domain‑specific rule. - Merge If Needed
Sometimes you need to combine fields from both revisions before committing the winner. - Delete the Losers
Send aDELETErequest for each unwanted_rev:curl -X DELETE http://localhost:5984/mydb/notes/123?rev=2-def456 - Compact the Database
After deleting the losing revisions, run a manual compaction to reclaim space:curl -X POST http://localhost:5984/mydb/_compact
4. Concrete Example – Two Nodes, One Document
Assume two CouchDB instances, nodeA and nodeB, each replicating mydb. Two clients write document doc1 concurrently:
- Client 1 on
nodeAwrites:curl -X PUT http://nodeA:5984/mydb/doc1 -d '{"title":"First"}' - Client 2 on
nodeBwrites at the same time:curl -X PUT http://nodeB:5984/mydb/doc1 -d '{"title":"Second"}' - After replication,
nodeAshows:{"_id":"doc1","_rev":"2-ghi789","title":"First","conflicts":["2-jkl012"]} - The application retrieves the conflict:
curl -X GET http://nodeA:5984/mydb/doc1?conflicts=true - It decides that the “Second” value is authoritative, merges if necessary, and deletes the losing revision:
curl -X DELETE http://nodeA:5984/mydb/doc1?rev=2-ghi789 - Finally, it compacts:
curl -X POST http://nodeA:5984/mydb/_compact
After these steps, both nodes hold the same single revision, and the database size drops.
Trade‑Offs and Limitations
- Manual vs Automated – Automating conflict resolution requires careful design to avoid data loss. Simple “last write wins” can be implemented with
_revcomparison, but more complex merges need business logic. - Storage Overhead – Each unresolved conflict consumes disk space. Without periodic compaction the database can grow linearly with the number of conflicts.
- Replication Lag – Conflicts propagate to all replicas, so a delayed replica may see divergent data longer than intended.
Actionable Checklist for Engineers
- Enable
?conflicts=truein critical read paths to surface divergence early. - Implement idempotent conflict‑resolution logic that can be replayed safely.
- Schedule nightly compaction or use
auto_compactionfor databases with high write churn. - Monitor
_changesstreams for unexpected conflict patterns. - Document the chosen resolution strategy in your architecture guide.
By understanding how CouchDB stores and surfaces conflicts, you can design robust distributed applications that keep data consistent without sacrificing storage efficiency.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.