The CAP theorem is easy to state, hard to apply, and almost universally misunderstood. It is the most common shorthand in distributed systems discussions, usually invoked by someone asserting that their database is CP or AP, with an implied understanding that the other person will nod as though this has clarified anything.
If you can state what the theorem actually claims — and what it does not — you will be ahead of most people in most system design conversations. This article gets you there.
The theorem in one sentence
Eric Brewer's original formulation: in a distributed data store, during a network partition, you must choose between consistency and availability.
That is it. Everything else is interpretation.
The three letters stand for:
- Consistency (C): every read sees the most recent write, or an error.
- Availability (A): every request gets a non-error response, possibly with stale data.
- Partition tolerance (P): the system keeps working when the network between nodes fails.
The common phrasing — "you can only have two of three" — is technically true but misleading. In any real distributed system, partitions happen. You do not get to opt out of P. So the practical choice is between C and A, and only during a partition.
What "partition" actually means
A partition is not just a dramatic data-centre failure. A partition is any situation where two nodes in the system cannot talk to each other for a period. This happens constantly at small scales: a packet drops, a TCP connection times out, a switch is upgraded, a rack loses power, a zone loses network.
The relevant question is not whether partitions happen — they do — but how your system behaves during one. That is what the CAP theorem forces you to think about.
A node on one side of the partition receives a write. The other side cannot know about it. If someone now reads from the other side, the system has two options:
- Refuse the read (or refuse the original write) because it cannot guarantee consistency. This is choosing C over A.
- Serve the read with the stale data that side has. This is choosing A over C.
There is no third option that magically preserves both. That is the theorem.
The false choices most explanations peddle
"We chose to be a CP system."
This usually means "we would rather return errors than stale reads during a partition." It does not mean the system is unavailable in normal operation — only that it sacrifices availability under partition. Systems like etcd, ZooKeeper, and Google's Spanner behave this way, which is appropriate for things like configuration and coordination where stale data is actively harmful.
"We chose to be an AP system."
This usually means "we would rather return stale data than errors during a partition." The system remains available under partition at the cost of temporarily inconsistent reads. DynamoDB (by default), Cassandra, and Riak behave this way, which is appropriate for shopping carts, social feeds, and anything where a slightly stale answer beats no answer.
The framing is too binary
Most modern databases are not strictly CP or AP. They are tunable: the system gives you knobs to choose, per operation, whether to prioritise consistency or availability. DynamoDB lets you request strongly consistent reads for specific calls. Cassandra lets you set a consistency level per query (ONE, QUORUM, ALL). Calling these "AP systems" is an oversimplification.
How it shows up in practice
Consider a typical cross-region deployment. You have a database in us-east-1 and a replica in eu-west-1. The link between them is mostly reliable, but occasionally congested or briefly broken.
During normal operation, writes go to us-east-1 and are replicated asynchronously to eu-west-1. A European user reads from eu-west-1 and might see data that is 50-500 ms behind us-east-1. This is eventual consistency, and it is fine for most applications.
A partition occurs: the link between the regions drops. Now us-east-1 accepts writes but cannot replicate them. eu-west-1 has stale data. What should eu-west-1 do?
- Serve stale reads (AP behaviour). Users in Europe see data that is minutes or hours behind.
- Reject reads (CP behaviour). European users see errors or timeouts.
- Also accept writes (multi-primary). Now you have two divergent states that will need to be reconciled when the partition heals, and you need to handle conflicts (last-write-wins, CRDTs, operational transformation).
There is no configuration of the system that avoids this choice. Your job is to make the choice deliberately.
BROKEN during partition| DB2 User1[US user
writes order] --> App1 User2[EU user
reads order] --> App2 App2 --> Decision{Partition detected.
What to do?} Decision -->|Serve stale data
AP behaviour| Stale[Return old snapshot] Decision -->|Reject request
CP behaviour| Error[Return 503] Decision -->|Accept local write
multi-primary| Conflict[Risk: divergent state
to reconcile later] style Stale fill:#fef3c7,stroke:#92400e,color:#451a03 style Error fill:#fee2e2,stroke:#991b1b,color:#450a0a style Conflict fill:#fde68a,stroke:#b45309,color:#451a03
A network partition between two regions forces a choice between consistency and availability. There is no fourth option.
PACELC: the forgotten extension
Daniel Abadi proposed an extension to CAP that is more practically useful: PACELC. It says: in the case of a Partition, you choose between Availability and Consistency; Else, you choose between Latency and Consistency.
The second half is what CAP misses. Even when there is no partition, a distributed system trades latency against consistency. Do you wait for a synchronous replication to a remote replica (higher latency, stronger consistency), or do you return as soon as the primary has acknowledged (lower latency, weaker consistency)? This decision happens on every write and drives the latency numbers you quote in your SLOs.
Most serious engineers have internalised PACELC even if they have not heard the name. It is worth knowing because it captures the tradeoff that matters most of the time (there is no partition) rather than the one that matters rarely (there is one).
Why CAP is less useful than it seems
Once you start designing real systems, the CAP classification begins to feel thin. A few reasons:
Most systems have many components
Your application writes to Postgres, reads from Redis, logs to Kafka, stores files in S3, searches Elasticsearch. Each of those has its own CAP tradeoffs, and the interesting behaviour is in how they compose. Asking "is your system CP or AP?" elides all of that.
Consistency is a spectrum, not a binary
Strict linearizability, sequential consistency, causal consistency, read-your-writes consistency, eventual consistency. Real systems offer different guarantees for different operations. "C" in CAP refers specifically to linearizability, which most systems do not actually provide and most applications do not actually need.
Availability is also a spectrum
Does "available" mean "serves all requests" or "serves most requests with occasional errors"? The theorem assumes the strict version; real SLOs are almost never strict.
Partitions are not the only failure mode
Disks fill up. Nodes slow down without fully failing. A bad deployment corrupts data without partitioning anything. CAP addresses one failure mode in a design space with many.
What to actually use
For system design conversations, CAP is useful as a starting point for discussing partition behaviour specifically. Beyond that, reach for more granular vocabulary: consistency models (linearizable, sequential, causal, eventual), replication strategies (synchronous, asynchronous, quorum), and failure modes (fail-stop, Byzantine, partial).
If you are picking a database, do not ask "is it CP or AP?". Ask: what consistency guarantees does it provide, configurably, under which failure conditions, at what latency cost? The answer is always more nuanced than two letters.
Frequently Asked Questions
Is MongoDB CP or AP?
Default MongoDB with replica sets is closer to CP — writes go to the primary, and if a majority of nodes cannot be reached, writes fail. But read preferences let you read from secondaries with eventual consistency. The honest answer is that it is tunable, and asking the CP/AP question is the wrong framing.
Why do people say "CAP is dead" or "CAP is misleading"?
Because the binary framing does not match real systems. Eric Brewer himself wrote a 2012 article titled "CAP Twelve Years Later" walking back the simpler interpretations. The theorem is still mathematically true; its usefulness as a design heuristic is what is contested.
What about Google Spanner? It claims to be CP and always available.
Spanner achieves global consistency by combining strong replication with GPS and atomic clocks to bound clock skew, which lets it provide externally consistent transactions. It is technically CP, but its availability in practice is extremely high because the infrastructure investment required to reduce partitions is enormous. Spanner is what happens when you throw a decade of engineering at the problem.
Share your thoughts
Worked with this in production and have a story to share, or disagree with a tradeoff? Email us at support@mybytenest.com — we read everything.