The CAP theorem is usually taught with a triangle: three corners labeled Consistency, Availability, Partition tolerance, and the stern instruction to “pick two.” It’s the most-drawn diagram in distributed systems, and it’s teaching people the wrong thing. You don’t pick two of three. You never really pick one of them at all.
Here’s the fix that makes CAP click: partition tolerance isn’t a choice. Networks drop packets, links fail, nodes lose sight of each other — whether or not your architecture is ready. So “P” is a fact of life, not an option on a menu. Which means the real decision only shows up during a partition, and it’s a straight two-way fork: stay consistent or stay available. This post is part of the System Design Foundations series, anchored by the System Design Building Blocks overview, and it’s the last building block on the map.
- You don’t pick partition tolerance — networks fail regardless, so a real distributed system must tolerate partitions.
- The only real choice is C vs A, and only during a partition: refuse to answer to stay correct, or answer with possibly-stale data to stay up.
- CAP ignores latency. PACELC adds the trade you pay even when nothing is broken: consistency costs coordination, which costs speed.
What CAP Actually Says#
Three precise definitions, because the loose ones cause all the confusion. Consistency here means every read sees the most recent write — all nodes agree on the latest value (formally, linearizability). Availability means every request gets a non-error response, even if a node can’t be sure it has the freshest data. Partition tolerance means the system keeps operating even when the network drops or delays messages between nodes. The theorem, proven by Gilbert and Lynch from Brewer’s conjecture, says you can’t have all three at once when a partition is happening.
The word “when” is doing heavy lifting, and most explanations drop it.
Why “Pick Two” Is Wrong#
Play it out. Suppose you tried to “sacrifice” partition tolerance to keep C and A. That means building a system that assumes the network never fails — and the first dropped packet takes the whole thing down, so you’ve built neither consistent nor available, just fragile. Because you can’t wish partitions away, every distributed system is partition-tolerant by necessity. That collapses the triangle: the genuine decision is what to do while the network is split.
Read both sides. A write updated x to 2 on the other side of a break, and a read arrives at Node B, which still holds the old x = 1. The CP system refuses — it returns an error rather than risk handing back a stale value: correct, but unavailable. The AP system answers with x = 1 anyway — available, but stale. Same partition, two philosophies. Eric Brewer, revisiting his own theorem in CAP Twelve Years Later, says exactly this: the “two of three” formulation is misleading, because you only give up C or A, and only during a partition.
CP vs AP: The Choice During a Partition#
The whole decision reduces to one question: when a node can’t confirm it’s current, is a wrong answer worse than no answer?
In code, it’s one line of policy:
def read(key):
if not reached_quorum(): # can't confirm we hold the latest
raise Unavailable() # CP: refuse rather than risk stale
# return local_value(key) # AP: answer anyway, maybe stale
return quorum_value(key)| CP — choose consistency | AP — choose availability | |
|---|---|---|
| On a partition | Return an error / block | Return possibly-stale data |
| You’d rather | Say “I don’t know” than lie | Answer, even if slightly wrong |
| Fits | Balances, inventory, config, locks | Carts, feeds, DNS, metrics |
| Examples | etcd, ZooKeeper, most RDBMS | Cassandra, DynamoDB (tunable), DNS |
If a stale read causes a real-world error — double-selling the last item, showing a wrong balance — you want CP: it’s better to fail loudly than to be confidently wrong. If being down is the bigger harm and slightly-old data is survivable — a social feed, a shopping cart that reconciles later — you want AP. Neither camp is more advanced; they’re answers to different questions about which failure you can live with.
The Trap: CAP’s “Consistency” Isn’t ACID’s#
One more source of endless confusion. The C in CAP is not the C in ACID. CAP consistency is about every node agreeing on the latest value across a network; ACID consistency is about a single database honoring its own rules and constraints within a transaction. A system can be ACID-compliant and still be an AP system in CAP terms. When someone says “consistency,” it’s worth knowing which one they mean.
The Part CAP Ignores: Latency#
CAP only speaks about the moment of a partition — but partitions are rare, and it says nothing about the other 99.9% of the time. That’s the gap PACELC fills: if Partition, trade Availability vs Consistency; Else, trade Latency vs Consistency. As ScyllaDB’s rundown puts it, even with no failure at all, stronger consistency means more nodes must coordinate before answering — and coordination is latency. So the trade you dodge with CAP you still pay every single day in milliseconds.
The honest framing: CAP isn’t “pick two of three.” It’s “you already have partition tolerance, so pick C or A during a partition” — and, PACELC adds, “pick how much latency you’ll pay for consistency the rest of the time.” Every distributed system is answering both, whether the team said so out loud or not.
Martin Kleppmann’s critique of CAP pushes further: the neat CP/AP labels oversimplify real databases, which often sit somewhere in between with tunable guarantees. Treat CAP as a thinking tool that frames the trade-off, not a filing system that sorts every database into a box.
CAP Inside an AI System#
The CAP trade doesn’t disappear in AI systems — it hides inside components you might not think of as “distributed databases.”
Your RAG index is eventually consistent, and that’s an AP choice. When you add a document, its embedding is written and the vector index updates asynchronously — for a window, a search won’t find the thing you just ingested. That’s availability-over-consistency by design, the same call vector databases make so writes don’t block reads. If your app promises “upload and it’s instantly searchable,” you’ve picked a consistency requirement the index may not meet.
A stale semantic cache is literally choosing A over C. Serving a cached answer to a question whose underlying data has changed is availability at the cost of consistency — which is why caching needs a deliberate staleness window, not a default. And agent memory raises the classic trap: a user expects the assistant to remember what they just said (read-your-writes consistency), but if conversation state lives across replicas, a stale read makes the agent look like it has amnesia — so agent memory is a place to lean CP for the parts that must be current.
AI-era rule of thumb: your vector index and semantic cache are quietly AP (eventually consistent) — fine for search and cost savings, dangerous if you promised freshness. Keep agent/session state closer to CP so the assistant never forgets what the user just told it.
Quick Recap#
- Partition tolerance isn’t optional — networks fail, so every distributed system has it.
- The real choice is C vs A, only during a partition: error out to stay correct, or serve stale to stay up.
- CP for correctness-critical, AP for availability-critical — decide which failure hurts less.
- PACELC adds latency: even with no partition, consistency costs coordination time.
- In AI systems, RAG indexes and semantic caches are AP by nature; keep agent state nearer CP.
Conclusion#
The CAP theorem finally makes sense the moment you throw away the triangle. You’re not choosing two of three properties like toppings — you’re accepting that the network will break, and deciding what your system should do when it does: hand back a wrong answer, or hand back no answer. That single decision, made deliberately per piece of your system rather than inherited by accident, is what CAP is really for. And once the partition passes, PACELC reminds you the trade never fully goes away — you’re always paying somewhere between latency and consistency. Pick on purpose, per component, and know which kind of failure you chose to live with.
Where have you been bitten — a CP system that went down when you needed an answer, or an AP system that served stale data at the worst possible moment? Tell me which one bit you.
- Caching Strategies — staleness as a deliberate availability-over-consistency choice.
- Kafka vs RabbitMQ — how a durable log gives eventually-consistent consumers a way to catch up.
- System Design Building Blocks — the decision map this completes.

