Articles
CouchDB Interview Questions: MVCC, Revision Conflicts, and Replication
Explain CouchDB MVCC, stale writes, replicated conflicts, winning revisions, and safe merges with a revision-tree exercise and interview practice.
Two offline clients edit the same CouchDB document. After replication, a normal read returns one version, and both replicas agree on that version. Has the conflict been resolved? Readers have a deterministic winner, but the business conflict may remain. The application may still be hiding a valid change on another branch.
CouchDB interview questions test whether you can separate a stale write, a replicated conflict, and a business merge. This article follows an original address-edit example through revision checks, divergent leaves, and a repair that can survive another writer.
Official facts come from stable Apache CouchDB 3.5 documentation. The documents, revision labels, and resolution procedure are original exercises and design inference. They are not candidate reports or evidence of a specific employer's interview. Pair the explanation with Design an Offline-First Client That Syncs Edits and Resolves Multi-Device Conflicts.
What does MVCC mean for a document update?
Official fact: CouchDB uses multiversion concurrency control, and its ordinary document update API requires the current revision identifier when replacing an existing document. A stale revision causes a conflict response rather than silently replacing a newer state. See eventual consistency and the document API.
Treat _rev as an opaque concurrency token. Its familiar shape contains a generation number and a suffix, but the suffix is not an application timestamp, and the number is not a global database sequence. Do not sort revision strings to reconstruct business chronology across documents.
For an original example, read:
{
"_id": "shipping::42",
"_rev": "1-a",
"city": "Boston",
"postal_code": "02110",
"delivery_note": "Front desk"
}
The short revisions in this article are symbolic teaching labels, not real hashes to send to a database. A client replaces this document using the actual revision returned by its read. On success, it receives a new revision token. Another client still holding the old token cannot assume that its replacement remains valid.
A strong answer explains the unit of protection. Revision checking protects this document update against an obsolete document version. It does not automatically enforce an invariant involving several independently updated documents. For an order and an inventory record, state how the workflow maintains the cross-document rule rather than claiming MVCC supplies an arbitrary multi-document transaction.
Also distinguish atomic replacement from semantic correctness. A replacement can be accepted against the current revision and still contain the wrong address. Concurrency control tells you whether the version changed; application validation tells you whether the proposed content is acceptable.
How is an HTTP 409 different from a replicated conflict?
Official fact: CouchDB's replication and conflict model distinguishes conflicts prevented during ordinary updates from divergent revisions introduced through replication. A deterministic winning revision is selected for ordinary reads, while other live leaf revisions can remain present.
Consider two different timelines:
| Situation | What happened | What the client must do |
|---|---|---|
| Stale ordinary update | Two clients read one server; one updates before the other's replacement | Read the current revision and re-evaluate the proposed change after the 409 |
| Replicated divergence | Disconnected replicas each accept a local update from a shared ancestor | Inspect live branches and apply a domain-specific resolution policy |
In the first case, the rejected write did not automatically create a new accepted conflict branch. Retrying the same obsolete payload and token repeats the problem. In the second, both edits may already be valid local writes. Connectivity recovery exposes their divergence; it does not make one edit invalid merely because it loses ordinary winner selection.
That distinction changes the user experience. A connected editor can show a “changed since you opened it” message when a conditional update fails. An offline editor may need to show an unresolved conflict discovered later during synchronization. Reusing the same generic “retry failed” message for both situations hides whether the user's change was accepted anywhere.
A diagnostic answer should identify the replica that accepted each write, the shared ancestor, the current leaf revisions, and the time replication occurred. A single current _rev is insufficient to prove that no alternative branch exists.
Does the winning revision contain the right business answer?
Follow this original address exercise. Both clients begin from symbolic revision 1-a. Client North changes the delivery note to “Side entrance,” creating 2-b. Client South changes the city and postal code together to Cambridge and 02139, creating 2-c.
After replication, the revision tree has two live leaves:
1-a
├── 2-b: Boston, 02110, Side entrance
└── 2-c: Cambridge, 02139, Front desk
Suppose a normal read exposes 2-c. That statement is an assumed outcome for the exercise, not a claim that those symbolic suffixes reproduce CouchDB's actual winner algorithm. The business requirement is to preserve the address change and the independent delivery-note change if they remain compatible.
One proposed result is Cambridge, 02139, “Side entrance.” But say why the fields can be combined. City and postal code form a related pair; merging each field independently can produce an invalid address. The delivery note may also refer to the old building. If the application cannot establish compatibility, ask for review instead of presenting the combined document as unquestionably correct.
Now change the exercise so both clients edit the postal code differently. There is no obvious field union. Possible policies include a trusted source, explicit user choice, or a domain rule with an audit trail. “Take the largest revision number” supplies no business justification.
The answer should therefore separate deterministic database visibility from semantic resolution. Agreement between replicas on the winner is useful for stable reads, but it is not proof that the winner incorporates every intended edit.
How do you inspect the hidden branches?
Official fact: the document API supports requesting conflict information and retrieving open revisions. open_revs=all can return deleted as well as live leaves, so filter according to _deleted when identifying unresolved live alternatives. The document API options define the response shapes.
Use these illustrative requests against your own database and real identifiers:
GET /addresses/shipping%3A%3A42?conflicts=true
GET /addresses/shipping%3A%3A42?open_revs=all
The first helps reveal alternative revision identifiers alongside the visible document. The second lets the application examine leaf contents. Treat successful and missing revision entries explicitly rather than assuming every requested revision body is available.
Record the leaf identifiers used for the proposed merge. Without that set, a repair process cannot explain which changes it considered. If another branch arrives during replication, you need to distinguish “already incorporated” from “not yet examined.”
Do not build the process around fetching a complete historical document body for every ancestor. Compaction and revision pruning limit what can be reconstructed. If the merge needs field-level provenance, operation records, or a business audit trail, design that information into the application instead of assuming the revision tree is a permanent history service.
For the address exercise, the resolver should also know which fields each user intended to change. Comparing two full replacements can suggest intent, but it may be ambiguous when clients normalize fields or overwrite defaults. An explicit operation description can make the domain policy easier to defend.
What does a safe resolution trace look like?
Here is a design procedure derived from the example:
- Read the current live leaves and their revision tokens.
- Validate each branch and identify the edits to preserve.
- Construct a proposed merged document with a documented domain policy.
- Write that content as a new revision descending from a chosen current leaf, using its actual
_rev. - Retire the other incorporated live branches using their own revision tokens.
- Read the leaves again and verify that no unresolved live branch remains.
Official fact: CouchDB's conflict documentation describes updating one branch with merged content and deleting the other conflicting leaves. Deletion creates deleted revisions; it does not erase those branches from the revision tree.
Do not imply that this multi-request procedure is one atomic transaction. A merge write can succeed while a later branch deletion fails. Another writer or replication can introduce a new leaf between the steps. Preserve enough repair state to recognize completed work and repeat the inspection safely.
Suppose the resolver reads 2-b and 2-c, writes merged 3-d on the 2-c branch, and then encounters a conflict while trying to retire 2-b. It should inspect the current tree. If 2-b now has a live child, deleting that child without reading it could discard a new edit that the merge never incorporated.
Likewise, if the merge write itself is rejected because the selected branch advanced, re-read and recompute. Replacing the failed token with the latest token while retaining an old merge body is a blind overwrite wearing the appearance of a concurrency check.
Bound automated retries. Return an unresolved state when the policy needs a person or when contention exceeds the retry budget. Keep an audit record describing the inputs, policy, and resulting document so that “resolved” can be explained later.
What survives replication and compaction?
Official fact: CouchDB replication transfers document revisions between a source and target; a replication direction is explicit. Bidirectional synchronization is built from directions rather than assumed from the word “replicate.”
A continuous replication job still needs operational observation: source and target identity, connectivity, progress, errors, and whether the expected documents have arrived. It is not enough to show that the replication job was created.
For an original verification exercise, update an address at replica North, confirm it locally, and observe arrival at South. Then make divergent offline updates and verify that the conflict leaves propagate. These checks establish two different behaviors: ordinary transfer and divergence preservation.
Official fact: compaction discards bodies of non-leaf revisions while retaining revision information needed for replication and conflict handling, subject to pruning. The conflict documentation describes this boundary. Consequently, _rev is not a substitute for version-control history or a backup archive.
Explain deletion separately from erasure. A deleted revision participates in synchronization, helping prevent an old replica from casually restoring a document as if the deletion never happened. A purge is a different administrative operation and should not be proposed as routine conflict repair.
If the interviewer asks for recovery from an accidental destructive edit, ask what backup and application audit data exist. Replication may faithfully propagate the unwanted change. The fact that two replicas agree does not establish that either retains the prior business content required for recovery.
How would you test the resolver?
Use a small deterministic fixture rather than a large random dataset first. Test independent edits, conflicting edits to one field, an invalid city/postal-code combination, and a deleted document competing with an update. For each, assert the intended policy result and the remaining live-leaf count.
Then inject failures at the boundaries: after writing the merged content, before retiring another branch, and while another client advances a leaf. The resolver must preserve a newly arrived change or report that further resolution is needed. Merely reaching one visible document is not a sufficient assertion.
Test repeated execution as well. A repair worker can crash and restart. It should inspect state and avoid treating its previous merged result as a new independent business action. Where side effects are involved, use a stable resolution identifier and an explicit deduplication contract.
These tests are an application design recommendation, not evidence that a real CouchDB cluster was exercised for this article. The point is to make the claim “we resolved the conflict” observable through branch contents and domain outcomes.
Practice conflict handling beyond the API
| Question | What to carry into the answer |
|---|---|
| Design an Offline-First Client That Syncs Edits and Resolves Multi-Device Conflicts | Separate accepted offline edits from later conflict resolution. |
| Design Calendar Event Conflict Handling | Define which business edits can be combined. |
| Design a replicated cloud storage service | Explain divergence, synchronization and deletion. |
| Design a Distributed File System | Keep replication separate from recovery history. |
| Design a Synchronously Replicated Hash Map | Compare acknowledgment requirements with an offline replication model. |
Start with the offline-first conflict exercise. Draw every live leaf, propose a merge policy, and explain what happens if another edit arrives halfway through repair.