Every engineer "knows" CAP. Most can recite the letters. A surprising number can't say what C, A, and P actually mean, or that the theorem has a very specific scope that makes most casual invocations of it wrong.
The most common symptom is the architecture review where someone says "we chose availability over consistency" about a system where the database is healthy, the network is fine, and nothing is partitioned. That sentence, in that context, doesn't mean anything. It sounds like a decision; it's actually a category error.
The actual theorem
CAP was formulated by Eric Brewer in 2000 and proved by Gilbert and Lynch in 2002. The formal statement is: a distributed system cannot simultaneously guarantee all three of the following properties when a network partition occurs.
The key phrase is "when a network partition occurs." Not "in general." Not "always." CAP says nothing about what tradeoffs your system makes when everything is working. It is a theorem about a specific failure mode.
The three properties, with their actual meanings rather than the folk versions:
Consistency (C) in CAP means linearizability. Every operation appears to take effect instantaneously at some point between its start and its completion, and the order of effects is consistent with the real-time order of operations. In plain language: reads always reflect the most recent write, and there's one agreed-upon history of events. This is stronger than "no stale reads." It's about the entire ordering of operations across all clients.
Availability (A) means every request received by a non-failing node gets a response. Not a fast response. Not a correct response. A response. A system that returns an error for reads during a partition is not available in the CAP sense, even if it's up and running fine.
Partition tolerance (P) means the system keeps operating despite messages being lost or delayed between nodes. This one is the source of the most confusion, because it's not actually a choice. You cannot turn off partitions. Networks are unreliable. The only question is what your system does when a partition happens. P is not a design decision; it's a constraint you always have.
So "choose between CP and AP" really means: given that you will eventually face a partition, do you want to stop accepting writes to maintain linearizability, or keep accepting writes and accept that different parts of the system might diverge temporarily?
Why the framing misleads
The CP/AP binary is seductive because it sounds decisive. In practice it obscures more than it reveals.
Take Cassandra, which is frequently described as an AP system. Cassandra has tunable consistency. With a replication factor of 3, you can configure reads and writes to require a quorum (2 of 3 nodes). Under those settings, during a partition that isolates one node, a quorum is still reachable and you get consistent reads. With weaker settings, say consistency level ONE, you'll get responses even from the isolated node, meaning you can read stale data. So is Cassandra AP? It depends on how you've configured it and how severe the partition is.
ZooKeeper is described as CP. It uses a majority-quorum protocol (ZAB) and will refuse writes if it can't establish a quorum, classic CP behavior. But if you're reading from a follower node using the "watch" API in certain configurations, you can still get stale reads for a brief window after a leader change. It's mostly CP, with caveats.
Real systems are not clean points on the CP/AP axis. They make different tradeoffs at different layers, often with knobs you can turn. Labeling them "CP" or "AP" flattens the actual behavior into a bumper sticker.
What actually matters day-to-day
Your system is probably not partitioned right now. Partitions are real but relatively rare. The tradeoffs you feel every day are not about partitions. They're about the relationship between latency and consistency under normal operating conditions.
When you write to a leader and read from a follower that's 50ms behind, that's not a CAP tradeoff. That's a replication lag tradeoff. When you do an eventually-consistent read to avoid a round-trip to the primary, that's a latency vs. staleness tradeoff. CAP doesn't describe either of these.
Daniel Abadi proposed a more useful model in 2010 called PACELC. The idea: if there's a partition (P), you trade availability vs. consistency (A vs. C), which is the CAP part. But else (E), during normal operation, you trade latency vs. consistency (L vs. C). Most real engineering decisions live in the "else" branch.
A system like DynamoDB is PA/EL: available during partitions, low-latency with eventual consistency under normal operation. A system like Google Spanner is PC/EC: consistent during partitions at the cost of availability, and consistent with higher latency under normal operation. These are actually different things that CAP collapses together.
The question worth asking
The next time someone says "we're an AP system" in an architecture discussion, ask them: what happens to writes during a network partition between your primary and your replicas?
If the answer is "writes keep going to the primary and replicas catch up later," you have partition tolerance with some consistency degradation, probably close to AP. If the answer is "we stop accepting writes until quorum is re-established," you're closer to CP. If the answer is "we haven't really thought about it," you have your answer.
The partition scenario is a forcing function. It makes you specify what you actually want. A system that hasn't been designed with that question in mind will make a choice for you when the partition happens, and it probably won't be the choice you'd have made on purpose.
CAP is not a design philosophy. It's a theorem about a corner case. Use it for what it's good at: reasoning about what must give during the specific failure mode of a network partition. For everything else, PACELC is a more honest map of the territory.
Back to writing