CAP Theorem Cheat Sheet
Explains Consistency, Availability, and Partition tolerance trade-offs in distributed databases and how real systems position themselves on the CAP spectrum.
CAP Theorem Definitions
The three properties the theorem trades off.
- Consistency (C)- Every read receives the most recent write or an error; all nodes see the same data at the same time
- Availability (A)- Every request receives a (non-error) response, without guarantee it contains the most recent write
- Partition tolerance (P)- The system continues operating despite network failures that drop or delay messages between nodes
- The theorem- During a network partition, a distributed system must choose between Consistency and Availability — it cannot guarantee both
- P is not optional- Network partitions will happen in any real distributed system, so practically the choice is always CP vs AP, not whether to have P
CP vs AP in Practice
How real database systems position themselves.
- CP systems- Prioritize consistency during a partition, may reject requests or return errors rather than stale/conflicting data (e.g., HBase, MongoDB with majority read/write concern, ZooKeeper, etcd)
- AP systems- Prioritize availability during a partition, may return stale data rather than an error (e.g., Cassandra, DynamoDB, Riak with eventual consistency settings)
- Tunable consistency- Many modern systems (Cassandra, DynamoDB) let you choose consistency level per-query (e.g., QUORUM, ONE, ALL) rather than being fixed CP or AP
- Single-node / no partition- CAP only applies to distributed systems facing an actual partition; a single-node relational database is trivially both C and A absent a network split
Partition Scenario
How CP and AP systems respond when a node is cut off.
# Cluster of 3 nodes (A, B, C) replicating a key "balance"# Network partition splits A | B,C# CP choice: node A refuses writes/reads (or returns an error)# because it cannot confirm it has the latest value with quorumcurl -X PUT nodeA/balance -d '100' # -> 503 Service Unavailable# AP choice: node A accepts the write locally and will# reconcile/merge with B,C once the partition healscurl -X PUT nodeA/balance -d '100' # -> 200 OK (may conflict later)# On healing, AP systems reconcile via last-write-wins,# vector clocks, or CRDTs depending on the database
Beyond CAP: PACELC
A refinement that accounts for latency even without a partition.
- PACELC extension- If Partitioned, choose between Availability and Consistency (as in CAP); Else (no partition), choose between Latency and Consistency
- Why it matters- CAP only describes partition behavior; PACELC acknowledges that even without a partition, synchronous replication for consistency adds latency
- Example- DynamoDB is PA/EL (favors availability during a partition, low latency normally); Postgres with synchronous replication is PC/EC (favors consistency both times)
Quorum Consistency Math
How read/write quorum sizing determines whether a tunable-consistency store behaves as strongly or eventually consistent.
N = number of replicasW = nodes that must ack a writeR = nodes queried on a read# Strong consistency guarantee when:W + R > N# Example: N=3W=2, R=2 -> 2+2=4 > 3 => strongly consistent, tolerates 1 node downW=1, R=1 -> 1+1=2 !> 3 => eventually consistent, fastest, least safeW=3, R=1 -> 3+1=4 > 3 => consistent reads, but write fails if any node down# Cassandra / DynamoDB expose this as per-query consistency levels:# ONE, QUORUM, ALL (Cassandra) or eventual vs strong (DynamoDB)
Detecting Conflicts with Vector Clocks
How AP systems detect concurrent, conflicting writes across replicas instead of silently picking a winner.
# Each replica increments its own counter on write# Vector clock: {nodeA: count, nodeB: count, nodeC: count}# Client writes to node A while partitioned from B, Cwrite(key="cart:42", value=["shoes"], clock={A:1, B:0, C:0})# Concurrently, another client writes to node Bwrite(key="cart:42", value=["hat"], clock={A:0, B:1, C:0})# On partition heal, neither clock dominates the other# (A:1,B:0 vs A:0,B:1 -> concurrent, not ancestor/descendant)# => sibling values are returned to the application to merge# (e.g., Riak) or resolved via last-write-wins timestamp (Cassandra)resolve("cart:42") => merge(["shoes"], ["hat"]) = ["shoes", "hat"]
Consensus Protocols vs CAP
How Raft/Paxos-based systems fit into the CAP framing.
- Consensus = CP by construction- Raft, Paxos, and Multi-Paxos require a majority quorum to commit; a minority partition simply cannot make progress, which is a deliberate CP choice
- Leader election on partition- If the leader is on the minority side of a partition, the majority side elects a new leader after a timeout; the minority side rejects writes (fencing) to avoid split-brain
- etcd / ZooKeeper / Consul- All built on Raft (etcd, Consul) or ZAB (ZooKeeper); used precisely because they favor consistency over availability for coordination/config data
- Why not use Raft for everything- Consensus adds a network round trip per write for quorum ack, so it trades throughput/latency for safety — fine for control-plane metadata, often too slow for high-volume data-plane writes
- Multi-Raft / sharded consensus- Systems like CockroachDB and TiDB run one independent Raft group per data range/shard instead of a single global group, so a partition affecting one range doesn't stall unrelated ranges
Session Guarantees Between Strict C and Eventual
Intermediate consistency models that many AP systems offer as a practical middle ground.
# Read-your-writes: a client always sees its own prior writes,# even if other clients might see stale datawrite(session=S1, key="profile:1", value={name: "Ann"})read(session=S1, key="profile:1") # guaranteed to return "Ann"# Monotonic reads: once a client sees a value, it never sees# an older value on subsequent reads within the same session# Causal consistency: writes that are causally related# (e.g., a comment after a post) are seen in that order by all clients,# but unrelated writes may be reordered# DynamoDB, Cosmos DB, and MongoDB all expose one or more of# these as configurable session/consistency levels between# strict linearizability and plain eventual consistency
Real-World System Positioning
How specific databases map onto the CAP/PACELC spectrum in default configuration.
- Spanner / CockroachDB- CP with a twist: use synchronized clocks (TrueTime) or hybrid logical clocks plus Raft/Paxos to offer near-global strong consistency with high (but not unlimited) availability
- MongoDB (majority write/read concern)- CP: primary steps down and rejects writes without a reachable majority; default read concern can still read stale data from a lagging secondary
- Cassandra (default QUORUM)- Tunable, defaults toward AP; can be pushed to CP-like behavior with ALL consistency level at the cost of availability
- Redis Cluster- AP by default (async replication, can lose acknowledged writes on failover); WAIT command trades latency for stronger durability guarantees
- Kafka- CP for a given partition: acks=all with min.insync.replicas enforces a write quorum before ack, sacrificing availability during under-replication
Don't treat CAP as a permanent label on a database product — most real systems let you tune the trade-off per operation (e.g., DynamoDB's eventually-consistent vs strongly-consistent reads, Cassandra's consistency levels), so the real design decision is per-query, not per-database.