Back to blog
Architecture
IntermediateForBackend EngineersPlatform EngineersSoftware Architects
7 min

The CAP Theorem, Honestly: What It Really Means When You Pick a Database

The CAP theorem is not 'pick two of three.' Partitions aren't optional, so the real choice is consistency vs availability during a network split — plus PACELC for the 99% of the time nothing is broken. A practical guide to choosing a database.

cap-theoremdistributed-systemsconsistencyavailabilitydatabase-selectionpacelcsystem-design
Contents

Every database comparison eventually reaches for the same triangle. Consistency, Availability, Partition tolerance — pick two. It looks clean, it fits on a slide, and it is wrong in the way that quietly costs you an outage.

The CAP theorem is real and it is useful. But the “pick two of three” version has misled a generation of system design interviews. Partitions are not a property you opt into. They are what the network does to you on a Tuesday afternoon. Once you see that, CAP stops being a party trick and becomes an actual tool for choosing where your data lives.

Consistency, Availability, Partition tolerance — the triangle everyone draws, and the choice it actually forces.

This is the honest version: what the three letters really mean, the one decision CAP forces, and how to turn it into a database choice you can defend.

Three Words That Don’t Mean What You Think

Before the trade-off, the definitions — because most CAP arguments are really vocabulary arguments.

  • Consistency here is linearizability: every read returns the most recent write, as if there were a single copy of the data. This is not the “C” in ACID. Same letter, different universe.
  • Availability means every request to a non-failing node gets a (non-error) response. Not “fast,” not “usually up” — an actual answer, every time.
  • Partition tolerance means the system keeps operating even when the network drops or delays messages between nodes.

Read those again and the myth falls apart on its own. A distributed database runs across a network. Networks partition — a switch dies, a cable is cut, a cloud AZ goes dark. You do not get to not tolerate that. P is not on the menu.

The Only Choice CAP Actually Forces

So if partition tolerance is mandatory, what is the theorem really about? A single, sharp moment.

When a partition splits your cluster into two groups that can’t talk, each side faces a question about a piece of data it can’t fully verify:

  • Stay consistent (CP): refuse to answer unless you’re sure you have the latest state. The minority side rejects writes, maybe rejects reads, and waits for the network to heal. Correct, but temporarily unavailable.
  • Stay available (AP): answer anyway, from whatever this replica knows, and reconcile the divergence later. Always responsive, but possibly serving stale data.

That is the whole theorem. Not “two of three” — C or A, and only while a partition lasts. When the network is healthy, you happily have both. CAP describes the behaviour of a system under a fault, not its permanent personality.

During a partition, one side must choose: block to stay correct (CP), or answer with stale data to stay available (AP).

A bank moving money picks CP: a double-spend is worse than an error message. A social feed picks AP: a slightly stale like count is invisible; a spinner is not.

The Part CAP Leaves Out: The Other 99% of the Time

Here is the trap that “pick two” hides completely. Partitions are rare. A well-run cluster spends the overwhelming majority of its life fully connected. CAP says nothing about that time — and that time is where you actually live.

This is why PACELC matters. It extends CAP to the normal case:

If there is a Partition, choose Availability or Consistency — Else (L), when everything is healthy, choose Latency or Consistency.

That second clause is the decision you make on every request. Strong consistency isn’t free even when the network is perfect: confirming that a read reflects the latest write means coordinating across replicas, and coordination costs milliseconds. Loosen consistency and reads get faster; tighten it and they get slower but truer.

So the real, daily trade-off is not the dramatic outage scenario. It is: how much latency will you pay, on the happy path, to be certain your data is current? That question fires millions of times a day. The partition question fires once a quarter.

It’s Per-Operation, Not Per-Database

The other thing the triangle gets wrong: consistency and availability are not fixed traits stamped on a database. They are choices you make per operation.

Most modern distributed stores expose this directly through quorums. With N replicas, a read waits for R responses and a write for W acknowledgements. Set R + W > N and any read is guaranteed to see the latest committed write — strong consistency, higher latency. Set them lower and you trade freshness for speed.

-- Cassandra: choose the trade-off per statement.
-- Strong: read and write quorums overlap (R + W > N).
CONSISTENCY QUORUM;
INSERT INTO ledger (acct, delta) VALUES ('A42', -100);
-- Fast and available: answer from the nearest replica, accept staleness.
CONSISTENCY ONE;
SELECT likes FROM post WHERE id = 'p_9f3';

The same cluster is CP for the ledger write and AP for the like count. You are not choosing a database’s philosophy; you are choosing the guarantee this specific request needs. DynamoDB has its ConsistentRead flag, Cosmos DB ships five consistency levels, MongoDB has read/write concerns. The label on the box is a default, not a destiny.

So Where Do the Databases Actually Land?

Defaults still matter, because they are what you get before you tune anything. Roughly:

  • Lean CP — Google Spanner, HBase, etcd, ZooKeeper, MongoDB (default majority). They will reject or block during a partition to protect correctness. Spanner is the interesting one: it’s CP by design but spends enormous engineering — TrueTime, redundant private networking — to make partitions so rare that it feels highly available.
  • Lean AP — Cassandra, DynamoDB, Riak, CouchDB. They keep answering during a split and reconcile afterward with mechanisms like last-write-wins or CRDTs.

A rough map: CP stores block to stay correct, AP stores answer to stay available, and PACELC adds the everyday latency axis.

And the myth to bury: there is no useful “CA” database. “CA” only describes a single node with no network to partition — a lone Postgres instance. The instant you replicate or shard it, Postgres faces the exact same CP-versus-AP choice as everything else. If a design doc calls something “CA,” someone is reading the triangle, not the system.

How to Actually Choose

Skip the triangle. Ask three questions in order.

  1. What is the invariant that must never break? If two users can spend the same balance, or two orders can claim the last unit of stock, you need CP on that path. Correctness first; a rejected request is recoverable, a corrupted invariant often is not.
  2. What can tolerate being slightly stale? Carts, feeds, view counts, recommendations, sessions, telemetry — a few seconds behind is invisible to users and worth the availability and speed. That’s AP, and it’s most of your traffic.
  3. What latency can the happy path afford? This is the PACELC question. If a read must be strongly consistent and p99 under 10ms, you’re asking for coordination on a deadline — budget for it, or relax one of the two.

Then design the partition explicitly instead of hoping it never comes. Make writes idempotent so a retry after a heal is safe. Use fencing tokens so a stale leader can’t act. Put money and identity behind quorum reads; let the feed serve from the nearest replica. Same cluster, different guarantees, chosen on purpose.

Choosing the store is one decision; keeping the traffic to it sane is another. For the messaging side of a resilient system, see Pub/Sub or Eventarc? Event-Driven GCP Without the Spaghetti and Send 1,000,000 Notifications Without Falling Over.

The Field Rule

The CAP theorem is not a triangle you pick two corners of. Partitions are guaranteed, so partition tolerance is fixed. The real choice is one moment — during a split, do you block to stay correct (CP) or answer to stay available (AP)? — and PACELC handles the other 99% of the time, where you trade latency for consistency on every request. Decide it per operation, not per database: protect the invariants that can’t break, relax everything that can tolerate a little staleness, and design the partition on purpose. Do that and “which database” stops being a religious war and becomes what it should be — a trade-off you made with your eyes open.

Frequently asked questions

What is the CAP theorem in simple terms?

The CAP theorem says that when a network partition splits a distributed system in two, you cannot have both consistency (every read sees the latest write) and availability (every node still answers). You must sacrifice one. It does not mean 'pick two of three' — partition tolerance is not optional because networks fail on their own schedule. The only real choice is consistency versus availability while a partition is happening.

Does CAP mean I can only pick two of the three properties?

No — that framing is the most common misunderstanding. A distributed system that talks over a network must tolerate partitions, so P is fixed. The theorem is really a statement about a single moment: during a partition, do you keep answering with data that might be stale (AP), or do you refuse to answer to stay correct (CP)? The rest of the time, when the network is healthy, you get both C and A.

What is the difference between a CP and an AP database?

During a network partition, a CP system chooses correctness: nodes that can't confirm the latest state reject reads or writes rather than return stale data. An AP system chooses to keep answering, accepting that some replicas may be behind and reconcile later. HBase, Spanner and etcd lean CP; Cassandra and DynamoDB lean AP. Many modern databases let you tune this per operation with quorum settings.

What is PACELC and how does it extend CAP?

PACELC extends CAP to the normal case. It reads: if there is a Partition (P), choose Availability or Consistency (A/C); Else (E), when the system is running healthy, choose Latency or Consistency (L/C). It matters because partitions are rare, but the latency-versus-consistency trade-off happens on every single request. PACELC describes the decision you actually make all day, not just during an outage.

Is PostgreSQL a CA database?

Not in any useful sense. The 'CA' label only describes a single-node system with no network between replicas — and a single node has nothing to partition, so CAP simply doesn't apply. The moment you add replication or sharding, Postgres faces the same CP-versus-AP choice as everyone else. Treat 'CA' as a sign someone is misreading the theorem, not as a category to design for.

From the community

Discussion on the Fediverse

Replies from Mastodon and Bluesky — straight from the open web, no tracking.

Loading replies …

ENDE