The CAP Theorem — Why Distributed Systems Can't Have It All
A bank-branch deposit scenario that breaks down what Consistency, Availability, and Partition Tolerance actually mean, why "pick two" is misleading, and how to actually choose in practice.
Most people first hear about the CAP theorem as "pick two": Consistency, Availability, Partition Tolerance — you can only have two out of three. It's a catchy line, and it's also spread a lot of confusion, including among engineers who went on to design real systems without ever being clear on what tradeoff they'd actually made. This post breaks CAP down properly: what it actually says, why "pick two" isn't quite right, and how to use it to make real decisions.
Picture two bank branches sharing a ledger
Say a bank has two branches, each keeping its own copy of your account balance, and the two databases sync with each other in the background. You deposit $1,000. Branch A updates its balance to $1,000 right away, then forwards that update to Branch B, which updates its own copy too. As long as the network between them holds up, both branches always show the same number.
But what happens if the connection between A and B drops? If someone walks into Branch B and asks for their balance right at that moment, what should Branch B do? It's got two options:
- Be honest: "I can't reach Branch A right now, so I can't guarantee this number is current."
- Answer with whatever it has on hand, so the customer at least gets a number, and reconcile once the network comes back.
That dilemma — what to do once the network breaks — is exactly what the CAP theorem is about.
What C, A, and P actually stand for
CAP stands for three properties that describe a tradeoff every distributed system — one made of multiple machines that each hold data and sync with each other — has to make:
- Consistency: every node sees the same data at the same time. In the branch example, satisfying consistency means A and B always report the same balance, no matter when you ask.
- Availability: every request gets a response. The system doesn't just refuse to answer because something's wrong internally — even if a node can't reach the others, it still responds instead of hanging.
- Partition tolerance: the system keeps working even when the network between nodes drops packets, disconnects, or latency spikes. This kind of network trouble is collectively called a network partition.
The original claim is that a distributed system can satisfy at most two of these three properties at once.
Why "pick two" is misleading
Here's the catch: partition tolerance isn't really optional. Any system built out of multiple machines connected over a network will experience partitions sooner or later — the only question is how often. You can't design a system that "opts out" of partition tolerance, because whether the network breaks isn't up to you.
So the real decision was never "pick two out of C, A, and P." It's this: when a partition actually happens, does the system choose consistency or availability? That's why you'll often see CAP reframed as a choice between CP and AP.
Back to the bank example:
- Choosing CP (Consistency + Partition Tolerance): when the network drops, Branch B refuses to answer. It would rather leave the customer without a balance than risk giving out a number that might be stale.
- Choosing AP (Availability + Partition Tolerance): Branch B answers with whatever data it has, prioritizing a response over accuracy, and reconciles once the network is back. Data read during this window might be stale — a state known as eventual consistency.
It clicks faster with real systems
- Systems that lean CP: things like ZooKeeper and etcd, used for distributed coordination and leader election, along with core banking transfer systems. They'd rather go temporarily unavailable than let two nodes disagree — because if they disagree, real money stops adding up.
- Systems that lean AP: databases like Cassandra and DynamoDB, built for high-traffic use cases like shopping carts, activity feeds, or like counts. They'd rather hand back a slightly stale answer than let a single disconnected node take the whole service down.
Neither approach is "better" — it comes down to whether your use case can tolerate briefly stale data, or whether it can't tolerate not getting data at all.
CAP isn't a strict either/or
Two common misconceptions are worth clearing up here.
First, the CAP tradeoff only kicks in during a partition. When the network is healthy, a system can be both consistent and available at the same time. CAP describes what happens specifically during a partition — it doesn't mean a system is permanently stuck as "a C system" or "an A system."
Second, consistency isn't all-or-nothing — it's a spectrum. On one end there's strong consistency, where every read returns the most recently written value. On the other, eventual consistency, where data converges over time. In between sit various middle grounds, like read-your-writes, which guarantees you'll always see your own writes even if you might not see someone else's yet. Choosing AP doesn't mean your data is forever inconsistent — it just means you're not guaranteeing it's consistent right now.
How to actually choose
When you're designing a system, instead of asking "is my system CP or AP," start with the business question: if this feature's data is briefly inconsistent, can users live with that? If it's briefly unavailable instead, can they live with that?
- For anything involving money, inventory deduction, or authentication — cases where getting it wrong is a real problem — lean CP: better to go down briefly than to return a wrong answer.
- For things like social feeds, comments, or browsing history, where seeing it a little late doesn't matter, lean AP: keep the feature usable, and let the data catch up later.
And within a single system, different features can absolutely make different choices — you don't have to commit the whole system to one tradeoff.
Wrapping up
CAP is often reduced to "pick two," but the more accurate way to think about it is this: in any real distributed system, partition tolerance is essentially a given, not a choice. The actual design decision is whether to favor consistency or availability when a partition hits. Once that clicks, looking at how ZooKeeper or Cassandra are built stops being a matter of memorizing labels — you can actually see what problem they're solving and what they're willing to give up to solve it.