MongoDBConsistency Model

MongoDB's Consistency Model

MongoDB is often described as "eventually consistent," but that undersells it — it offers a genuinely tunable consistency model, letting each operation choose its own point between fast-but-loose and slow-but-strict. This page ties together replica set mechanics, read/write concerns, and CAP theorem positioning into one coherent picture.

Replica Set Consistency Basics

Every replica set has one primary accepting writes at a time, and secondaries that asynchronously replicate the primary's oplog. Because replication is asynchronous by default, a secondary can lag behind the primary by anywhere from milliseconds to (under load or network issues) seconds.

  • Reads directed to the primary always see the latest acknowledged write.

  • Reads directed to a secondary may see slightly stale data, depending on replication lag.

  • A write acknowledged with w: 1 and then immediately followed by a primary failover, before replication completed, can in rare cases be rolled back.

Read-Your-Own-Writes with Majority + Causal Sessions

The combination of writeConcern: "majority" and a causally consistent client session gives you a strong, practical guarantee: your own subsequent reads will reflect your own prior writes, regardless of which replica set member actually serves the read.

JS
const session = client.startSession({ causalConsistency: true })

await orders.updateOne(
  { _id: orderId },
  { $set: { status: "shipped" } },
  { session, writeConcern: { w: "majority" } }
)

// This read is guaranteed to observe the update above
const order = await orders.findOne(
  { _id: orderId },
  { session, readConcern: { level: "majority" } }
)
Stale Reads from Secondaries

Without a causally consistent session, reading from a secondary (readPreference: "secondary" or "secondaryPreferred") can return data that is behind the primary by however much that secondary is lagging. This is a deliberate tradeoff you opt into for read scaling or geographic locality — not a bug.

JS
// Explicitly accepting potentially stale reads in exchange for
// distributing read load across secondaries
db.products.find({ category: "electronics" })
  .readPref("secondaryPreferred")
Warning
Never route reads that immediately follow a critical write (payment confirmation, inventory decrement) to a secondary without a causally consistent session — the user could see pre-write state seconds after their own action succeeded.
Tunable Consistency via Concerns

This is the actual mechanism behind "tunable consistency" — you are not choosing a single global consistency level for the deployment, you choose it per operation via read concern and write concern (see the dedicated Read/Write Concerns page for the full option reference).

Goal

Configuration

Maximum speed, can tolerate rare data loss/staleness

w:1, readConcern:local

Safe default for most application code

w:majority, readConcern:local

Strong read-after-write guarantee for a user's own actions

w:majority + causal session

Strongest single-document real-time guarantee

w:majority, readConcern:linearizable (primary only)

Consistent snapshot across multiple documents

Multi-document transaction with readConcern:snapshot

CAP Positioning

CAP theorem says a distributed system can only fully guarantee two of Consistency, Availability, and Partition tolerance at once. MongoDB is generally categorized as CP (consistent, partition-tolerant) by default: during a network partition, a replica set will not elect a primary without a majority of voting members, sacrificing write availability in the minority partition rather than risking inconsistent writes.

  • With a majority-based configuration, the minority side of a partition cannot accept writes — it has no primary. This favors consistency over availability during a partition.

  • Reading from secondaries with a weak read concern shifts you toward the AP end of the spectrum for that specific read — you trade consistency for availability/latency.

  • This is why MongoDB is more accurately described as "tunable" rather than strictly CP or AP — the classification depends on the concerns you choose per operation.

Practical Configuration Recipes

E-commerce checkout — must not lose or misread the order

JS
await session.withTransaction(async () => {
  await orders.insertOne(orderDoc, { session })
  await inventory.updateOne(
    { sku }, { $inc: { qty: -1 } }, { session }
  )
}, {
  readConcern: { level: "snapshot" },
  writeConcern: { w: "majority" }
})

Product catalog browsing — favor speed, staleness is fine

JS
db.products.find({ category: "electronics" })
  .readPref("secondaryPreferred")
  .readConcern("local")

Analytics dashboard — read scaled out, slight lag acceptable

JS
db.orders.aggregate(pipeline, {
  readPreference: "secondary",
  readConcern: { level: "available" }
})
Tip
Pick the consistency level per access pattern, not once for the whole application — a checkout flow and a product-browsing page have very different tolerance for staleness, and MongoDB lets you express that difference directly in each query.
Summary
  • Replication is asynchronous by default — secondaries can lag, and reads there can be stale.

  • Majority write concern + a causally consistent session gives practical read-your-own-writes guarantees.

  • MongoDB defaults toward CP under partition (no primary without a majority), but read concern lets individual operations lean toward AP when staleness is acceptable.

  • Configure consistency per operation, matched to what that specific read or write actually requires.