CAP Theorem and Read/Write Concerns
What the CAP Theorem Says
When data is stored on several servers (replicas or shards), the network between them can fail. The CAP theorem says that during such a network failure, a distributed database can guarantee only one of these two:
- Consistency (C): every read returns the latest write, or an error.
- Availability (A): every request gets a response, even if the data might be old.
The third letter is Partition tolerance (P): the system keeps working when the network splits servers into groups that can't talk to each other (a network partition). Networks do fail, so P isn't optional. The real choice is C or A when a partition happens.
Think of two bank branches whose phone line goes down. A customer asks branch B for their balance:
- Choose C: "Sorry, we can't confirm your balance right now." Correct, but no answer.
- Choose A: "Your balance is ₹500." An answer, but maybe outdated, if branch A just processed a withdrawal.
1 network partition2[ Primary ] ──────── ✂ ──────── [ Replica ]3 latest: wallet = ₹200 still has: wallet = ₹5004 5Read arrives at the replica:6 CP → refuse or wait → no wrong answer, but an error7 AP → return ₹500 → always answers, but staleNot the same C as ACID. ACID consistency means "rules and constraints hold". CAP consistency means "all copies agree on the latest value".
CP vs AP in Our App
Different data in the same app can make different choices:
| Data | Choose | Why |
|---|---|---|
| Wallet balance, payments | CP | Showing a wrong balance can cause double spending; an error is safer |
| Order status after payment | CP | The user must not see "unpaid" after paying |
| Restaurant menus, ratings | AP | Slightly old is fine; showing nothing loses customers |
| Rider location on the map | AP | A few seconds old is fine |
| CP | AP | |
|---|---|---|
| During a partition | Some requests fail or wait | All requests answered |
| Data returned | Always latest | Possibly stale |
| Good for | Money, inventory, bookings | Feeds, catalogs, counters, locations |
What About When the Network Is Fine?
CAP only describes failures. Most of the time the network works, and there's still a trade-off: waiting for replicas to confirm makes data safer but slower. This extension is called PACELC: during a Partition choose A or C; Else (normal operation) choose Latency or Consistency.
1Write wallet = ₹2002 wait for 1 server → ~2 ms → fast, a crash may lose it3 wait for majority → ~10 ms → slower, survives a primary crashThat everyday choice is what read and write concerns control.
MongoDB: Write Concern and Read Concern
Write concern answers: "How many servers must confirm a write before it counts as done?"
| Write concern | Meaning | Trade-off |
|---|---|---|
w: 1 | Primary confirms | Fast; write can be lost if the primary crashes before replicas copy it |
w: "majority" | Most replica set members confirm | Slower; survives a primary failover. Default since MongoDB 5.0 |
j: true | Also written to the on-disk journal | Survives a power cut on that server |
Read concern answers: "What data am I allowed to see?"
| Read concern | Meaning | Trade-off |
|---|---|---|
"local" | Latest data on this server, even if not yet on a majority | Fast; could later be rolled back (default) |
"majority" | Only data confirmed by a majority | Never rolled back; may be slightly behind |
"linearizable" | The latest majority-confirmed data, checked at read time | Strongest; slowest, primary only |
Read preference decides which server to read from: primary (latest) or secondary / secondaryPreferred (spreads load, may be stale).
Tuning these per operation is how you choose consistency or speed for each piece of data:
// wallet: must not be lost or staledb.wallets.updateOne({ userId: 42 },{ $inc: { balance: -300 } },{ writeConcern: { w: "majority", j: true } });db.wallets.find({ userId: 42 }).readConcern("majority").readPref("primary");// menu: fast, slightly stale is finedb.menuItems.find({ restaurantId: 7 }).readPref("secondaryPreferred");
Interview Angle
How to Explain it in an Interview
Common mistakes:
- Saying "pick any two of C, A, P". You can't give up P in a real network; the choice is C vs A during a partition.
- Confusing CAP consistency with ACID consistency.
- Labelling a whole database "CP" or "AP". Settings like write and read concern change its behaviour per operation.
Summary
1CAP → during a network partition: Consistency OR Availability2P → not optional, networks fail3CP → latest data or error → wallets, payments4AP → always answers, maybe stale → menus, locations5PACELC → no partition: latency vs consistency6Write concern → w:1 (fast) | w:"majority" (safe) | j:true (journaled)7Read concern → local (fast) | majority (no rollback) | linearizable (strongest)8Read preference → primary (latest) | secondary (spread load, may be stale)That wraps up scaling. Next, we move into the app side, starting with connection pooling: how Node.js apps share a limited number of database connections.