CAP Theorem and the PACELC Extension
Concept
The CAP theorem (Eric Brewer, 2000; formalized by Gilbert & Lynch, 2002) states that a distributed data store can provide at most two of three guarantees simultaneously:
- Consistency — every read sees the most recent write (or an error). All nodes agree on the current value.
- Availability — every request gets a non-error response, without a guarantee that it reflects the most recent write.
- Partition tolerance — the system keeps operating despite the network dropping or delaying messages between nodes.
The crucial, often-missed nuance: in any real distributed system, network partitions will happen — they are not optional. So partition tolerance is not a free choice; you must have it. That collapses CAP into a single real decision: when a partition occurs, do you sacrifice consistency (keep answering, possibly with stale data — AP) or sacrifice availability (refuse to answer rather than answer wrongly — CP)? "CA" systems (consistency + availability, no partition tolerance) only exist inside a single node or a network that never partitions, which is not a distributed system.
PACELC (Daniel Abadi, 2010/2012) fixes CAP's biggest blind spot: CAP only describes behavior during a partition, which is rare. PACELC extends it to normal operation. It reads: if Partition, choose between Availability and Consistency (PAC); Else, choose between Latency and Consistency (ELC). The insight is that even when the network is perfectly healthy, a replicated system still faces a consistency-vs-latency tradeoff on every single request — to guarantee a read sees the latest write, you must coordinate across replicas, which costs latency; to answer fast, you may serve a slightly stale replica. Partitions are rare; the latency-consistency tradeoff is paid on every request, all day, forever. That makes the "ELC" half the one that actually shapes most user-facing behavior.
The four PACELC classes: PA/EL (Dynamo, Cassandra — available under partition, fast otherwise, both at the cost of consistency), PC/EC (traditional RDBMS, Spanner-style — consistent always, paying availability under partition and latency otherwise), PA/EC and PC/EL (mixed — e.g. a system that stays available under partition but prefers consistency when healthy).
Tradeoffs
| Class | Under partition | Normal operation | Example systems |
|---|---|---|---|
| PA/EL | Stay available, allow stale reads | Favor low latency over strong consistency | Cassandra, DynamoDB (eventual), Riak |
| PC/EC | Refuse writes/reads that can't be made consistent | Pay coordination latency for strong consistency | Spanner, traditional single-leader RDBMS, VoltDB |
| PC/EL | Prefer consistency during partition | Favor latency when healthy | PNUTS |
| PA/EC | Stay available during partition | Prefer consistency when healthy | MongoDB (tunable), some configs |
The real design lever in most modern stores is that these are tunable per-operation, not fixed for the whole system — e.g. Cassandra's per-query consistency levels (ONE, QUORUM, ALL) let one workload be PA/EL and another PC/EC in the same cluster. The architecture decision is therefore rarely "pick a database class" and more often "pick a consistency level per read/write path based on what that path can tolerate."
When to use / when not to
- Use CAP/PACELC as a framing tool in any design review touching replicated state — it forces the question "what does a read return during a partition, and what latency does a consistent read cost when healthy?" out into the open where it can be decided deliberately.
- Reach for PACELC specifically (over bare CAP) whenever the system is read-heavy and latency-sensitive, because there the ELC tradeoff dominates the user experience far more than the rare partition does.
- Don't treat CAP as a literal "pick 2 of 3 checkbox" — it's widely misapplied that way. Partition tolerance isn't optional in a distributed system, and both C and A are spectrums (tunable per operation), not binary switches.
- Don't apply it to a single-node system — with no network between replicas, there's no partition to tolerate and no cross-replica latency tradeoff; CAP/PACELC has nothing to say.
Common pitfall
Treating "consistency" and "availability" as global, permanent properties of a chosen database rather than per-operation, tunable decisions. Teams say "we chose an AP database" and then are surprised when a QUORUM read blocks during a partition, or when an "eventually consistent" read returns stale data that breaks a balance check. The pitfall is skipping the per-path analysis: a payments ledger write and a "recently viewed items" read live in the same system but sit at opposite ends of the consistency-latency tradeoff, and treating them uniformly either over-pays latency on the trivial path or under-protects the critical one.
Engineering Lens
CAP/PACELC is one of the cleanest litmus tests for distributed-systems maturity in an architecture review: a junior answer picks a database and moves on; a Principal-level answer names, per data path, what a read returns during a partition and what a consistent read costs in latency when healthy — and shows those were chosen to match each path's actual tolerance. This reasoning is directly load-bearing in Fintech and Capital Markets: an account-balance or order-book read is PC (a stale balance is a correctness bug and potentially a compliance one), while a "trades near you" feed is PA/EL — and being able to articulate why those two paths sit in different PACELC classes, in the same system, is exactly the tradeoff-articulation skill these roles screen for.
Related
- Read Replicas and Replication Lag
- Distributed Consensus: Raft and Leader Election
- Database Sharding Strategies
- Saga Pattern