Distributed systems
CAP theorem: interview questions and how to answer them
CAP says that when a network partition occurs, a replicated data store must give up either linearizable reads and writes or the ability to answer every request — it does not say you choose two properties out of three.
Written and reviewed by Sahil Srivastav
What it actually is
The precise statement, from Gilbert and Lynch’s 2002 proof of Brewer’s conjecture, is this: in an asynchronous network where messages between nodes can be lost or arbitrarily delayed, no replicated register can simultaneously guarantee linearizability and total availability. That is the whole theorem. It is a statement about what happens during a partition, not a taxonomy of databases.
Each letter has a narrow technical meaning that everyday usage blurs. C is linearizability: every read observes the most recently completed write, as if there were a single copy of the data. A is total availability: every request that reaches a non-crashed node receives a non-error response, eventually. P is not a property you build but an assumption about the environment — that the network may drop messages between correct nodes.
Because P is an assumption rather than a feature, “pick two of three” is a misreading. If your nodes communicate over a network you do not control, partitions will happen; the design question is what the system does while one is in progress. Answer every request with possibly stale data (sacrifice C) or refuse to answer on the minority side (sacrifice A). Those are the only two options the proof leaves.
Why it matters in production
It determines the failure behaviour you are signing up for, which is a product decision as much as an engineering one. A shopping cart that accepts writes on both sides of a partition and merges them later is usually right; a ledger that does the same has just allowed a double spend. The interesting work in a design interview is arguing which of the two an operation belongs to, not reciting the acronym.
It also explains why leader-based systems become unavailable for writes on the minority side of a split. A Raft or Paxos group with three nodes and a 2–1 partition keeps serving from the majority and rejects the minority — that is not a bug in the implementation, it is CAP being obeyed. Candidates who cannot predict this behaviour usually cannot debug it either.
And the theorem is silent about the case that dominates real operations: no partition at all. That is the gap PACELC fills, and it is the reason a “CP” store can still be the wrong choice for a latency-sensitive read path.
How it works
The proof in one paragraph
Take two nodes, N1 and N2, replicating one value, and partition them. A client writes to N1, which cannot reach N2. A second client reads from N2. N2 must either return the old value — violating linearizability — or refuse to answer — violating availability. No algorithm escapes this, because N2 has no way to distinguish a partition from a slow network, which is the asynchronous-model assumption doing the work.
What C is not
The C in CAP is not the C in ACID. ACID consistency means the database enforces your declared integrity constraints; CAP consistency means reads and writes appear to happen in a single total order consistent with real time. A single-node PostgreSQL is fully ACID and trivially linearizable, and CAP has nothing to say about it, because there is nothing to partition.
What A is not
CAP availability is not an uptime percentage. It is the absolute property that every request to a live node gets a real answer. A system with 99.999% uptime that returns errors during a partition is, in CAP terms, not available. Conversely a “CP” system is not “less reliable” — it is trading answerability for correctness in one specific window.
PACELC: the half CAP omits
Abadi’s extension states it fully: if there is a Partition, trade Availability against Consistency; Else, trade Latency against Consistency. The second half is where most of your latency budget actually goes. Linearizable reads require either contacting a quorum or routing to the leader, so they cost at least one round trip and cannot be served from the nearest replica.
Consistency is a hierarchy, not a switch
Between linearizable and eventual there are useful intermediate models: sequential consistency, causal consistency, read-your-writes, monotonic reads. Causal consistency is the strongest model that remains fully available under partition, which is a far more interesting fact than “AP systems are eventually consistent”. Naming the model you need is what distinguishes a real design answer.
Implementing it
Decide per operation, not per database. In the same system, “add to cart” can be available and mergeable while “submit payment” routes to a leader and fails closed. Storing both in one Postgres instance does not make the distinction go away — it just means the failure mode is the whole instance.
If you choose availability, choose the merge function deliberately. Last-write-wins silently discards data and needs synchronised clocks to be even approximately correct; a CRDT or an explicit sibling-resolution callback keeps both writes. “We will resolve conflicts later” is not a design.
If you choose consistency, decide what the minority side does with the requests it cannot serve: fail fast with a retryable status, queue them for later application, or degrade to a read-only mode serving a known-stale snapshot with an explicit staleness bound.
Test the partition rather than reasoning about it. Blocking traffic between nodes with iptables or a fault-injection proxy, then asserting which operations still succeed, finds more design bugs than any amount of whiteboard argument.
Interview questions and how to answer them
State the CAP theorem precisely.
In an asynchronous network where messages between nodes may be lost, a replicated data store cannot guarantee both linearizability and total availability. During a partition it must give up one. I would add two clarifications: C means linearizability specifically, and A means every request to a live node gets a non-error response — not an uptime target.
Why is “CA” not a meaningful category?
Because P describes the environment. If nodes talk over a network that can drop messages, partitions occur whether or not you planned for them, so a system that claims C and A has simply not specified what it does when one happens — and in practice it stops being one or the other. A single machine is genuinely not partitionable, but then there is no replication for the theorem to constrain.
A three-node Raft cluster is partitioned 2–1. What does each side do?
The majority side elects or keeps a leader and continues to accept writes. The minority node cannot win an election because it cannot reach a quorum, so it rejects writes and — if the implementation is honest about it — rejects linearizable reads too, since it cannot prove it is still the leader. That is the consistency-over-availability choice being executed.
Your API must stay writable during a partition. What have you accepted?
That two sides can accept conflicting writes and that I own a merge strategy. Practically: version vectors or CRDTs rather than last-write-wins, an invariant set that tolerates temporary violation, and a compensating action for the cases it cannot. This is fine for a cart or a like counter and unacceptable for a uniqueness constraint such as seat allocation or a balance that must not go negative.
Does CAP mean you must choose between consistency and low latency?
CAP itself says nothing about latency; PACELC does. Even with a perfectly healthy network, a linearizable read must reach the leader or a quorum, which costs a round trip and forbids serving from the closest replica. So the everyday cost of strong consistency is latency, and the partition-time cost is availability.
What is the strongest consistency model that stays available under partition?
Causal consistency. It preserves the order of causally related operations while allowing concurrent operations to be seen in different orders, and it can be maintained without cross-partition coordination. Anything stronger — sequential or linearizable — requires agreement, which a partitioned minority cannot obtain.
Answers that lose the round
- Saying “pick two of three” — partition tolerance is a property of the network, not a choice, so the real trade-off is binary and only applies during a partition
- Calling a single-node relational database “CA”, which is a category the theorem does not define
- Conflating CAP’s C with ACID’s C, and therefore claiming Postgres “chooses consistency over availability” in the CAP sense
- Treating CAP availability as uptime, and so describing a system with a fast failover as “AP”
- Believing CAP forces a global choice for the whole system rather than per operation
- Forgetting that the consistency/latency trade-off applies when the network is healthy, which is most of the time — this is what PACELC adds
- Claiming a system is “strongly consistent” without saying which model: linearizable, sequentially consistent, and snapshot-isolated are three different promises
Practise cap theorem in a real repository
CAP becomes concrete the moment a read lands on a lagging replica. This Gronex repository has a write path that commits to the primary and a read path that immediately queries a replica; the tests assert read-your-writes for the caller who just wrote, so routing every read to the replica fails and routing every read to the primary throws away the capacity you added it for.
FAQ
Is MongoDB CP or AP?
It depends on settings, which is the honest answer to that question for almost every database. With `w: majority` writes and `readConcern: majority` or `linearizable`, the minority side of a partition refuses to serve, which is the consistency choice. With `w: 1` and reads from secondaries, you get stale reads and possible rollback of acknowledged writes. The label belongs to the configuration, not the product.
Is eventual consistency the same as AP?
Not quite. AP describes the partition behaviour; eventual consistency describes the guarantee — replicas converge if writes stop. An available system can offer much more than that, notably causal consistency and read-your-writes, and saying which one you need is the difference between a vague answer and a designed one.
Is CAP obsolete?
The theorem is a proof, so it is not obsolete; the marketing built on it is. Brewer himself wrote in 2012 that the “2 of 3” framing is misleading and that the useful questions are which invariants must hold during a partition and how to recover afterwards. Treat CAP as a constraint on the partition window and PACELC as the guide for the rest of the time.
Where do distributed transactions fit?
Two-phase commit is firmly on the consistency side: a participant that has voted yes and lost contact with the coordinator must hold its locks and wait rather than decide unilaterally, which is unavailability by construction. Saga-style compensating workflows trade that blocking for temporary visible inconsistency plus an undo path.