Skip to content
CAP Theorem Explained: Consistency, Availability, Partitions

Click to use (opens in a new tab)

CAP Theorem Explained: Consistency, Availability, Partitions

August 16, 2026 by Chat2DBChat2DB Team

The CAP theorem is the most cited and most misquoted result in distributed systems. You have probably seen the triangle diagram with "pick any two" written underneath, and possibly a chart sorting databases into CP and AP columns. Both are simplifications that mislead more than they explain.

The actual theorem is narrower, more precise and considerably more useful once you understand what it does and does not constrain.

What the three letters mean

The definitions are specific, and most confusion comes from using the everyday meanings instead.

Consistency here means linearizability, not the C in ACID. A system is linearizable if every read returns the value of the most recent completed write, as though there were a single copy of the data and all operations happened one at a time in some order. If a write completes at 10:00:00 and you read at 10:00:01 from any node, you must see that write.

This is a much stronger requirement than ACID consistency, which merely means a transaction moves the database from one valid state to another with respect to its constraints. A system can be fully ACID and not linearizable.

Availability means every request to a non-failing node receives a non-error response, in finite time. Note what this excludes: returning an error, or a timeout, counts as unavailable. Note also what it includes — there is no latency bound. A response after thirty seconds is technically available.

Partition tolerance means the system continues to operate when the network drops or delays arbitrary messages between nodes. A partition is not a node crashing; it is nodes that are alive but unable to talk to each other, each unable to distinguish "the others are down" from "I am cut off".

The theorem, stated properly

Proved by Gilbert and Lynch in 2002 (formalizing Brewer's 2000 conjecture), the result is:

In an asynchronous network where messages may be lost, it is impossible for a distributed system to guarantee both linearizable consistency and availability.

That is it. It says nothing about normal operation. It is a statement about what happens during a partition.

The reasoning is easy to follow. Take two nodes, A and B, holding a replicated value x = 1. The network between them fails. A client writes x = 2 to node A. A different client now reads x from node B. Node B has two options:

  1. Return x = 1 — it responds, so it is available, but the answer is stale, so the system is not linearizable.
  2. Refuse to answer until it can reach A — it preserves consistency, but it did not respond, so the system is not available.

There is no third option. B cannot know about the write, because the network is down. No amount of clever engineering escapes this, which is why the theorem is a genuine impossibility result rather than an engineering trade-off.

Why "pick two" is wrong

The triangle implies three symmetric choices: CA, CP, AP. But CA is not a real option for a distributed system.

Partitions are not something you choose to tolerate. They are something the network does to you. Cables get cut, switches fail, a misapplied firewall rule isolates a rack, a cloud availability zone loses connectivity. If your system spans more than one machine, partitions will happen.

So the choice is not among three options. It is: when a partition occurs, do you sacrifice consistency or availability? You must tolerate partitions; you get to choose how you degrade.

Systems labelled "CA" are typically single-node databases, where the question does not arise because there is no network between replicas. A single PostgreSQL instance is trivially consistent and available — and if the machine dies, it is neither.

What CP and AP look like in practice

CP systems refuse to serve requests they cannot answer correctly. The usual implementation is a consensus protocol — Raft or Paxos — where a write is acknowledged only after a majority of nodes agree. During a partition, the side with a majority keeps working; the minority side rejects requests.

The important consequence is that a minority partition is entirely unavailable, even for reads, if you want linearizable reads. In a five-node cluster split three-two, the two-node side stops serving. This is correct behaviour, and it is also downtime for anyone whose traffic lands there.

etcd, ZooKeeper, Consul, CockroachDB, Spanner and MongoDB with majority write and read concerns behave this way.

AP systems always respond, and accept that different nodes may temporarily disagree. Writes go to whatever nodes are reachable, and the divergence is reconciled afterwards — by last-write-wins timestamps, by vector clocks, by CRDTs, or by handing conflicting versions to the application.

Cassandra, DynamoDB (in its default configuration), Riak and CouchDB sit here.

The reconciliation strategy matters enormously and is where AP systems differ most. Last-write-wins is simple and silently discards data: two concurrent writes, one survives, the other vanishes with no error. CRDTs guarantee convergence without loss for the operations they support, but constrain your data model. Handing conflicts to the application is the most flexible and the most work.

Tunable consistency blurs the line

Most modern systems do not sit at a single point. Cassandra and DynamoDB let you choose per query.

In Cassandra, with a replication factor of 3:

-- Fast, may read stale data
CONSISTENCY ONE;
SELECT * FROM orders WHERE tenant_id = 42 AND id = 1001;
 
-- Strong: R + W > N guarantees overlap with the latest write
CONSISTENCY QUORUM;
SELECT * FROM orders WHERE tenant_id = 42 AND id = 1001;

The rule is R + W > N, where N is the replication factor, W is the nodes that must acknowledge a write, and R the nodes that must respond to a read. With N=3, W=2 and R=2, the read and write sets must overlap by at least one node, so a read always sees the latest acknowledged write. That is a consistency guarantee bought with availability: if two of three replicas are unreachable, quorum operations fail.

The same table can be queried at ONE for a dashboard and at QUORUM for a payment check. CAP applies per operation, not per database.

PostgreSQL offers a similar dial for its replication:

-- Asynchronous: primary commits without waiting. Fast; a failover can lose recent commits.
SET synchronous_commit = off;
 
-- Synchronous: primary waits for a standby to confirm. No data loss on failover;
-- if no standby responds, commits block.
SET synchronous_commit = remote_apply;

Setting synchronous_standby_names to require a standby, then losing that standby, means writes hang. That is CP behaviour, chosen by configuration.

The part CAP leaves out

Here is the practical objection to CAP as a design tool: partitions are rare. Most of the time your network is fine. CAP says nothing about that time, yet that is when your system spends 99.9% of its life.

Daniel Abadi's PACELC formulation fills the gap:

If there is a Partition, choose between Availability and Consistency; Else, choose between Latency and Consistency.

The second clause is the one that shapes daily experience. Even with a healthy network, a strongly consistent system must coordinate across nodes before acknowledging a write. That coordination costs a network round trip — a millisecond within a datacentre, tens of milliseconds across regions. Every strongly consistent cross-region write pays that.

Classified with PACELC:

  • PC/EC — consistent during partitions, consistent (and slower) normally: Spanner, CockroachDB, etcd, VoltDB.
  • PA/EL — available during partitions, low latency normally: Cassandra, DynamoDB (default), Riak.
  • PA/EC — available during partitions, but consistent when healthy: MongoDB's default configuration lands near here.

This tells you more about how a database will feel than the CP/AP label does, because it describes the common case.

Consistency models below linearizable

CAP's "consistency" is the strongest useful model, but there is a spectrum, and most applications are well served by something weaker.

Linearizable — reads always see the latest completed write. Required for leader election, distributed locks, uniqueness constraints, anything where a stale read causes a correctness bug.

Sequential consistency — all nodes see operations in the same order, but that order need not match real time.

Causal consistency — operations that are causally related appear in order everywhere; concurrent operations may be seen in different orders. This is enough for most collaborative applications: a reply never appears before the message it replies to.

Read-your-writes — a client always sees its own writes, though others may lag. This handles the single most visible staleness bug: a user edits their profile, the page reloads from a replica, and their change appears to have vanished.

Eventual consistency — replicas converge if writes stop. Says nothing about how long, or what you see meanwhile.

Read-your-writes is worth calling out because it is cheap and solves a disproportionate share of user-visible problems. If you use read replicas behind a primary, routing a user's reads to the primary for a few seconds after they write gives you most of the benefit of strong consistency at almost none of the cost.

Applying this to a real decision

Rather than asking "is my database CP or AP", ask what happens to each operation when a partition occurs.

For a payment authorisation, a stale read means authorising against a balance that no longer exists. Refusing the request is correct: an error the user can retry is better than money that does not exist. That operation wants CP.

For a product page view count, a stale read means a slightly wrong number. Refusing to render the page over that would be absurd. That operation wants AP.

For a username registration, you need a genuine uniqueness guarantee, which requires linearizability. You cannot get "mostly unique" from an eventually consistent store without a reconciliation process that decides which of two people who claimed the same name loses it.

For a shopping cart, Amazon's classic Dynamo answer is instructive: they chose availability, accepted that concurrent updates could conflict, and resolved conflicts by merging carts. An item unexpectedly reappearing is a minor annoyance; a cart that refuses to accept items costs a sale.

The same system routinely wants different answers for different operations, which is why per-query tunable consistency is so common in modern databases — and why a single CP or AP label on the whole database tells you so little.

If you work across several of these systems at once, being able to open PostgreSQL, MongoDB, Redis, ClickHouse and Cassandra-compatible endpoints from a single client saves a lot of context switching; Chat2DB (opens in a new tab) connects to 20+ databases and lets you write queries in natural language when you are working in an engine whose dialect you use less often.

Summary

The CAP theorem says that during a network partition you cannot have both linearizable consistency and availability. It says nothing about normal operation, and "pick two" is misleading because partition tolerance is imposed by the network rather than chosen. Use PACELC instead: it captures both the partition trade-off and the latency-versus-consistency trade-off you pay every day. Then make the decision per operation rather than per database — payments and uniqueness need strong consistency, view counts and carts do not, and most systems need both.