1. What Consistency, Availability, and Partition Tolerance Actually Mean
The CAP theorem describes any distributed data system — one where data is replicated across more than one node connected by a network — and it defines three formal properties. Consistency (in CAP's specific sense, equivalent to linearizability) means every read receives the result of the most recent write, or an error; from the outside, the system behaves as if there were only a single copy of the data, even though it's replicated. Availability means every request to a non-failing node receives a non-error response — with no guarantee that the response reflects the most recent write. Partition tolerance means the system continues to operate despite an arbitrary number of messages being dropped or delayed by the network between nodes.
The detail that trips people up is what "partition tolerance" is actually asking. It is not a feature you opt into — it's a statement about reality. Any system with more than one node communicating over a real network, even nodes in the same data center, can experience a partition: a switch fails, a cable is cut, a router misbehaves, or a long garbage-collection pause makes a healthy node look unreachable to everyone else. You cannot engineer a distributed system that is immune to this. So partition tolerance isn't a property you trade away for consistency and availability — it's the baseline condition every real distributed system has to survive.
Normal: [Node A] <--replication--> [Node B]
Partition: [Node A] X [Node B]
(network between A and B drops or delays messages;
both nodes are individually still up and reachable
by clients, they just can't talk to each other)
A client writes to Node A during the partition. Node B can no
longer confirm it has the latest value. Now what does Node B do
when a client asks it to read that same data?
That last question is the entire theorem in miniature. Node B has exactly two options when it can't confirm it's up to date: refuse to answer (protecting consistency at the cost of availability), or answer anyway with what it has (protecting availability at the cost of possibly serving stale data). There is no third option that gives you both — not because engineers haven't found it yet, but because it's provably impossible to guarantee both linearizable reads and a guaranteed response while nodes can't communicate.
CAP is very often mistaught as "you can pick any two of C, A, and P," as if CA were a valid third option alongside CP and AP. It isn't — a system that isn't partition tolerant is a system that has simply chosen to stop working (or stop being correct) the moment a partition occurs, which is not a real design choice for any system with more than one node on a real network. Section 2 makes the actual, narrower choice explicit.
2. The Real Choice: CP or AP During a Partition
Because partition tolerance isn't optional, CAP's real content is this: when a partition happens, a system must choose between consistency and availability for the duration of that partition. A CP system has nodes that, when they can't confirm they're in sync with the rest of the cluster, refuse to serve the request — returning an error or timing out — rather than risk returning stale or conflicting data. An AP system keeps every reachable node answering requests through the partition, accepting that different nodes may temporarily disagree about the current value.
Inventory count for a product = 1 remaining, replicated on
Node A (US-East) and Node B (US-West). A partition separates them.
Two customers, one hitting each region, both try to buy the last unit.
CP choice:
Node A holds the "authoritative" write path (e.g. via a leader,
see Week 10). Node B, unable to confirm it has the latest count,
REJECTS the purchase with an error/timeout rather than risk
overselling.
Result: one customer is correctly sold the item; the other sees
a "try again" error. Consistency preserved, availability lost
on Node B's side.
AP choice:
Both Node A and Node B accept the purchase, since both keep
answering regardless of sync state.
Result: both customers get a "purchase confirmed" response --
the item is oversold, and the discrepancy has to be reconciled
(refund, apology, backorder) after the partition heals.
Availability preserved, consistency lost during the partition.
Real systems map cleanly onto this axis: ZooKeeper, etcd, and traditional relational databases configured for synchronous replication are CP by design — they'd rather reject a write than risk an inconsistent one. Cassandra, DynamoDB (in its default configuration), and Riak lean AP, prioritizing that every request gets a response even if it's occasionally stale, with tunable knobs to shift the balance per operation. Neither choice is universally correct — it depends entirely on which failure mode Section 1's non-functional requirements (Week 1) say is worse for that specific piece of data: a rejected request, or a wrong answer.
One more nuance worth knowing for interviews: CAP only governs behavior during a partition. When the network is healthy, a well-designed system can serve both consistent and available responses — there's no tradeoff to make in the common case. PACELC extends the idea to cover that: if there's a Partition, choose between Availability and Consistency; Else (no partition), choose between Latency and Consistency. Even with a perfectly healthy network, waiting for stronger consistency guarantees (e.g. confirming a majority of replicas) costs latency — so the tradeoff between consistency and something else doesn't fully disappear even outside of a partition, it just changes from "availability" to "latency."
Real systems are rarely purely CP or purely AP across every operation — a payment record and a "user is typing" indicator in the same app can reasonably make opposite choices. The strongest interview answer names the specific piece of data, states which failure is worse for it (a rejected request vs. a wrong value), and only then declares CP or AP for that data — not for "the system" as a monolith.
3. Strong Consistency
Strong consistency (linearizability) guarantees that once a write completes, every subsequent read — from any node, by any client — reflects that write. The system behaves as if all requests passed through a single copy of the data, processed one at a time, even though it's actually replicated across multiple nodes. Achieving this generally requires coordination: a write isn't considered complete until enough replicas (often a majority — see Week 10) have acknowledged it, which adds latency compared to acknowledging a write to just one node.
Strong consistency is the right choice when serving stale data is actively dangerous. A bank transfer is the canonical example: if you read an account balance during a transfer and see the pre-transfer amount because you happened to hit a lagging replica, you could authorize a withdrawal against money that's already been moved elsewhere — a real correctness bug, not a cosmetic one. A CP database with synchronous replication or a single-leader write path (Week 5, Week 10) exists specifically to prevent this by making sure a read can't return an answer that's known to be stale.
It goes wrong in the opposite direction too: a system that markets itself as strongly consistent but actually replicates asynchronously will let exactly this kind of bug slip through under load — a flash-sale inventory count that's technically "eventually accurate" but briefly wrong is exactly the gap that lets a system oversell the last few units of a popular item, even though nobody intended to compromise on consistency.
Every strongly consistent write path pays for its guarantee in latency and, per Section 2, in availability during a partition. Reach for it deliberately — account balances, inventory counts near zero, anything where "briefly wrong" is a real-world incident — rather than defaulting to it everywhere out of caution, which quietly makes the whole system slower and less available than it needs to be.
4. Eventual & Causal Consistency
Eventual consistency guarantees only that, given no new writes, all replicas will converge to the same value — eventually, with no bound on how long that takes. In between, different nodes can legitimately return different (stale) answers to the same read. This is the consistency model behind DNS propagation and behind most AP databases' default behavior. It goes right when staleness is genuinely harmless: a "likes" counter that shows 4,102 instead of 4,103 for a few hundred milliseconds costs nothing real. It goes wrong when a user's own action isn't visible to them immediately — post a comment, refresh the page, and briefly not see your own comment because the read got routed to a replica that hasn't caught up — which reads as a bug even though the system is behaving exactly as an eventually consistent design intends.
Causal consistency sits between the two: it guarantees that if operation A causally influenced operation B (B happened because of, or after seeing, A), then every node must observe A before B. Writes that are causally unrelated (concurrent, with no dependency between them) can still be observed in different orders on different nodes — causal consistency doesn't demand a single global order, only that cause-and-effect relationships are respected everywhere.
Post P is published.
Comment C1 replies directly to P.
Comment C2 replies directly to C1.
Comment C3 is an unrelated top-level comment on P, posted around
the same time as C1.
Causal consistency REQUIRES every node to show:
P before C1 (C1 causally depends on P existing)
C1 before C2 (C2 causally depends on C1 existing)
Causal consistency PERMITS different nodes to show C1 and C3 in
either order relative to each other, since neither caused the
other -- they're concurrent, unrelated writes.
Causal consistency goes right in exactly the scenario above: a social feed that respects causality will never show a reply appearing before the comment it's replying to, even while it's perfectly fine for two unrelated comments to appear in a different order to different viewers. It goes wrong when a system only offers plain eventual consistency and doesn't track causal relationships at all — nothing stops a reply from propagating to some replica faster than the comment it depends on, so a viewer can briefly see a reply to a comment that, from their vantage point, doesn't exist yet. Causal consistency costs more to implement than plain eventual consistency (it requires tracking dependencies, often via version vectors) but far less than strong consistency, which is why it shows up as a deliberate middle-ground choice in collaborative and social systems.
A single application is rarely one consistency model end to end. A social app might use strong consistency for payment/credit records, causal consistency for comment threads, and plain eventual consistency for like counts and follower counts — all in the same product. Naming this per-data-type, rather than declaring one model for "the system," is exactly the reasoning Section 2's callout also asks for on the CP/AP question.
5. Hands-on Exercise
Classify a ride-sharing app's data by consistency needs
A ride-sharing app has two very different pieces of replicated state: each driver's live GPS location, and each completed trip's final fare/payment record. Apply this week's framework to both.
Requirements:
- For driver GPS location: state whether you'd choose CP or AP during a network partition between regions, and justify it against a concrete failure scenario (what's the actual cost of a stale location vs. a rejected location update?).
- For the completed-trip fare/payment record: make the same CP/AP call, with its own justification.
- Name the consistency model (strong, eventual, or causal) you'd use for each of the two data types, and explain in one sentence why it fits better than the other two options.
- Write out, step by step, what a client sees for driver location during a partition under your chosen model, and what a client sees for the payment record during the same partition under its chosen model.
- In two sentences, explain why it's correct for this single app to make two different CP/AP choices rather than one system-wide choice.
Ask yourself which failure is worse for each: for GPS location, is a stale dot on the map worse than the app refusing to update at all? For a payment record, is a rejected request worse than the possibility of two conflicting final amounts? The answers point in opposite directions, and that's the point of the exercise.
6. Knowledge Check
Four quick questions. Expand each to check your answer.
Q1
Why is "the CAP theorem means you pick any two of Consistency, Availability, and Partition tolerance" a misleading way to state it?
Why is "the CAP theorem means you pick any two of Consistency, Availability, and Partition tolerance" a misleading way to state it?
That framing implies "CA" (consistency and availability, no partition tolerance) is a real third option alongside CP and AP. It isn't: any distributed system with more than one node on a real network can experience a partition, so declining partition tolerance isn't a design choice, it's a system that stops working correctly the moment reality intervenes. The actual, narrower choice CAP describes is between C and A, and only during an active partition.
Q2
Formally, what does "Consistency" mean in the CAP theorem, and how is that different from a system just returning correct-looking data most of the time?
Formally, what does "Consistency" mean in the CAP theorem, and how is that different from a system just returning correct-looking data most of the time?
CAP's Consistency specifically means linearizability: every read returns the result of the most recent write, or an error — with no window in which a stale answer is returned as if it were current. A system that's usually correct but occasionally serves a stale value under specific timing conditions (like a lagging replica) does not satisfy CAP consistency, even if that window is rare in practice.
Q3
Why might a payment record use strong consistency while a "likes" counter on the same platform uses eventual consistency?
Why might a payment record use strong consistency while a "likes" counter on the same platform uses eventual consistency?
The choice depends on the cost of staleness for that specific data, not on a system-wide policy. A stale payment record can cause a real financial error — double-spending or an incorrect charge — so it's worth paying the coordination latency and reduced availability that strong consistency costs. A stale likes count causes no real harm and correcting it costs nothing to defer, so eventual consistency's lower latency and higher availability is the better trade for that data specifically.
Q4
How does causal consistency differ from both strong consistency and plain eventual consistency?
How does causal consistency differ from both strong consistency and plain eventual consistency?
Strong consistency demands a single global order for every operation, which is expensive to coordinate. Plain eventual consistency demands no ordering guarantee at all beyond eventual convergence, which is cheap but allows genuinely confusing orderings like a reply appearing before the comment it replies to. Causal consistency is the middle ground: it guarantees that operations with a cause-and-effect relationship are seen in that order everywhere, while still allowing truly unrelated, concurrent operations to be seen in different orders on different nodes — cheaper than strong consistency, but safer than plain eventual consistency for anything with dependencies.