Under a Partition, You Pick Consistency or Availability
The CAP Theorem
CAP stated honestly — the partition tradeoff between C and A — why "CP vs AP" oversimplifies, and how PACELC adds the latency dimension.
What you'll learn
- State CAP correctly as a choice made only during a partition
- Explain why CP/AP labels oversimplify real systems
- Extend the model with PACELC's latency tradeoff
The CAP theorem is the most cited and most misquoted idea in distributed systems. The popular version — “pick two of Consistency, Availability, Partition tolerance” — is misleading enough to be wrong. Let’s state it the way that actually helps you design.
What the three letters mean
- Consistency (C) — every read sees the most recent write. All nodes agree on the current value. (Note: this is linearizability, a stricter notion than the “C” in ACID — same letter, different idea.)
- Availability (A) — every request to a non-failed node gets a (non-error) response, even if the data might be stale.
- Partition tolerance (P) — the system keeps working when the network drops messages between nodes.
The honest statement
Here’s the part the “pick two” framing botches: in any real distributed system, partitions happen — networks fail, packets drop, links flap. So P is not optional. You don’t choose partition tolerance; the network imposes it on you.
Which means the real theorem is much narrower:
When a partition occurs, you must choose between Consistency and Availability. When there’s no partition, you can have both.
The choice only exists during a partition. Two nodes can’t reach each other; a write arrives. You have exactly two options:
- CP — refuse or block writes until the partition heals, so nobody reads stale data. You stayed consistent at the cost of availability.
- AP — keep accepting reads and writes on both sides, reconciling later. You stayed available at the cost of consistency (the sides temporarily disagree).
There is no third door. During a partition you cannot be both perfectly consistent and fully available — that’s the entire theorem.
Why “CP vs AP” oversimplifies
Labeling a database “CP” or “AP” is a useful shorthand but a leaky one, because:
- It’s per-operation, not per-database. One system can offer strong consistency for some operations and eventual for others. Many modern databases let you choose the consistency level per query.
- It’s a spectrum, not a switch. Between “every read is current” and “anything goes” lie many useful middle grounds (the next lesson’s consistency models).
- Availability is graded. “Available” in CAP means any response — real SLAs care about latency and partial degradation, which CAP says nothing about.
PACELC: the missing half
CAP only describes the partition case — but partitions are rare. What about the 99.9% of the time the network is fine? PACELC completes the picture:
If Partition (P): choose Availability or Consistency (A/C). Else (E): choose Latency or Consistency (L/C).
The insight: even with no partition, strong consistency has a price — to guarantee every read is current, nodes must coordinate, and coordination costs latency. So the everyday tradeoff isn’t C vs A; it’s C vs L. A system that synchronously replicates to a quorum before acking is slower than one that acks locally and replicates lazily.
| System | Partition (P) | Else (E) | Reading |
|---|---|---|---|
| Dynamo / Cassandra | A | L | available + low-latency, eventual |
| Spanner | C | C | consistent always, pays latency |
| MongoDB (replica set, majority) | C | A | minority side rejects writes under partition; low-latency when healthy |
| Postgres (single primary) | C | C | consistent; not partition-tolerant by design |
The JavaScript angle
You feel CAP/PACELC in the shape of your async code, not in theory. A write
that waits for a quorum is a slower await than one that returns the moment the
local node has it — the latency tradeoff is literally how long your promise takes
to resolve:
// MongoDB: the write concern *is* the PACELC dial, per operation.
// Low latency, weaker durability/consistency: ack as soon as the primary
// has it in memory. Fast `await`, but a crash can lose this write.
await orders.insertOne(order, { writeConcern: { w: 1 } });
// Stronger consistency/durability: wait for a majority of replicas to
// confirm before resolving. Slower `await` — you paid latency for safety.
await orders.insertOne(order, { writeConcern: { w: 'majority' } }); The same line of JS, two different points on the PACELC curve — chosen per write. CAP tells you the tradeoff exists; the consistency models in the next lesson tell you the useful settings between the extremes.