NoSQL
Consistency Models
Two users open the same Google Doc at the same moment. User A types a sentence. User B sees it appear within milliseconds — not after a page refresh, not after a delay. Now imagine a bank: User A transfers £500. The moment that transaction commits, every ATM, every app, every branch in the world must show the updated balance — instantly, no exceptions. These two systems make completely different promises about when data becomes visible. Those promises have a name: consistency models. And choosing the wrong one for your system can cost you data, users, or money.
What a Consistency Model Actually Is
A consistency model is a contract between your database and your application. It answers one question: after I write data, when is it guaranteed to be visible — and to whom?
In a single-server world this is trivial — you write, it's saved, anyone who reads gets it. But the moment you have multiple nodes, multiple data centres, or millions of concurrent users, the answer becomes nuanced. Data has to travel across networks, replicate across servers, and coordinate across processes — and that takes time.
The core tension — visualised:
Strong Consistency
Every read gets the latest write. Always.
Eventual Consistency
Reads converge to latest. Eventually.
Model 1 — Strong Consistency
With strong consistency, after a write completes, every subsequent read — from any node, any server, any region — will return that new value. No stale data. No exceptions. The system behaves as if there is only one copy of the data.
Real-world analogy:
Imagine a whiteboard in a conference room. When someone writes on it, everyone in the room sees it instantly — there's one physical board. Strong consistency works the same way: one authoritative truth, everyone sees it the moment it changes.
The scenario: You're at a bank. You deposit £1,000 at the ATM. You walk 10 steps to the counter and ask the teller your balance. Strong consistency guarantees the teller sees your deposit — even though you made it 10 seconds ago on a different system. Here's how MongoDB enforces this with read and write concerns:
// Strong consistency in MongoDB
// Write with majority concern — confirmed on most nodes
await db.collection('accounts').updateOne(
{ user_id: 'u_441' },
{ $inc: { balance: 1000 } },
{ writeConcern: { w: 'majority' } } // wait for majority to confirm
)
w: 'majority'
The write doesn't return success until more than half the replica set nodes have saved it. Slower — but guaranteed. If the primary node dies the next millisecond, the data is still safe on the majority nodes.
$inc: {"{ balance: 1000 }"}
$inc atomically increments a field by the given value. This is safer than read-then-write: you're not reading the balance, adding 1000, then writing it back (race condition risk). You're telling MongoDB "add 1000 to whatever the current value is" in a single atomic operation.
// Read with linearizable concern — guaranteed to see the latest write
const account = await db.collection('accounts').findOne(
{ user_id: 'u_441' },
{ readConcern: { level: 'linearizable' } }
)
console.log(`Balance: £${account.balance}`)
Balance: £1000 -- Read confirmed against majority of nodes -- Guaranteed to reflect all writes that completed before this read -- Latency: ~12ms (vs ~2ms for eventual consistency) -- Use for: financial balances, inventory counts, medical records
What just happened:
readConcern: linearizable — MongoDB contacts the majority of nodes to confirm it's reading from the current primary before returning the result. This prevents a stale read from a node that hasn't caught up yet. The read is slower — but it's guaranteed to be the latest value.
The cost: 12ms vs 2ms. That's 6x slower. For a bank balance — absolutely worth it. For a social media like counter — complete overkill.
Model 2 — Eventual Consistency
With eventual consistency, after a write, different nodes may return different values for a short window — but given enough time with no new writes, all nodes will converge to the same value. The key word is eventually — which in practice usually means milliseconds to seconds, not hours.
Real-world analogy:
Think of a news website. A journalist publishes an article. Some readers see it immediately. Others, on a cached server in a different region, see it 30 seconds later. Eventually everyone sees the new article. The brief window of inconsistency doesn't hurt anyone — and the system served millions of readers with no bottleneck.
The scenario: You're running a social platform. A user posts a status update. It should propagate to all 3 regional nodes — but you don't want the write to wait for all of them. You want to confirm immediately and let the sync happen in the background:
from cassandra.cluster import Cluster
from cassandra import ConsistencyLevel
from cassandra.query import SimpleStatement
session = Cluster(['us-east','eu-west','ap-south']).connect('social')
Cluster(['us-east','eu-west','ap-south']) — three Cassandra nodes in three regions. Writes go to all three eventually. The driver picks the closest node for each request automatically.
# Write with ONE consistency — only 1 node needs to confirm
post = SimpleStatement(
"INSERT INTO posts (user_id, post_id, body, ts) VALUES (%s, %s, %s, %s)",
consistency_level=ConsistencyLevel.ONE
)
session.execute(post, ('u_8821', uuid4(), 'Just shipped v3!', datetime.now()))
-- Write acknowledged by us-east in 1.3ms -- eu-west and ap-south will sync within ~80ms -- If a user in London reads right now (eu-west): -- Might see: post not yet visible (eu-west hasn't synced) -- If same user reads 200ms later: -- Will see: "Just shipped v3!" (synced — eventually consistent) -- Write latency: 1.3ms -- Strong consistency equivalent: ~45ms
Breaking it down:
ConsistencyLevel.ONE
One node confirms — done. The write returns in 1.3ms. Cassandra's gossip protocol handles syncing the other two nodes in the background. You traded perfect consistency for 35x better write latency.
Post invisible for ~80ms in eu-west
This is the eventual consistency window. For a social post, this is completely acceptable — nobody is harmed by a post being 80ms late to appear. For a bank balance, this would be catastrophic. Context is everything.
Model 3 — Read-Your-Writes Consistency
Read-your-writes is a middle ground that solves a specific and very common problem: you write something, then immediately read it back — and see the old value. This feels like a bug even when the system is working as designed.
Real-world analogy:
You update your profile photo on a social network. You refresh the page — and see your old photo. Five minutes later it shows the new one. This is eventual consistency without read-your-writes. It feels broken even though it technically isn't. Read-your-writes guarantees: you always see your own writes immediately, even if others might see them slightly later.
The scenario: A user updates their display name. They expect to see the new name immediately everywhere. Here's how DynamoDB implements read-your-writes:
import boto3
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table = dynamodb.Table('users')
# Write the updated display name
table.update_item(
Key={ 'user_id': 'u_4421' },
UpdateExpression='SET display_name = :name',
ExpressionAttributeValues={ ':name': 'Priya S.' }
)
UpdateExpression — DynamoDB's way of modifying specific fields without overwriting the entire item. SET display_name = :name updates only that field. The colon prefix (:name) marks it as an expression attribute value — prevents conflicts with reserved words.
# Read back immediately — with strongly consistent read
# This guarantees the user sees THEIR OWN latest write
response = table.get_item(
Key={ 'user_id': 'u_4421' },
ConsistentRead=True # strongly consistent — reads from primary
)
print(response['Item']['display_name'])
Priya S. -- ConsistentRead=True reads from the primary node -- Guarantees this user sees their own update immediately -- Other users reading via eventually consistent path: -- May see "Priya" for up to 100ms, then "Priya S." -- That's acceptable — they didn't make the change
The key insight:
ConsistentRead=True — DynamoDB reads directly from the primary node instead of a potentially-stale replica. The write just happened — the primary has it. Other users reading from replicas might see a brief delay, but the person who made the change sees it instantly.
When to use this pattern: Profile updates, settings changes, any "I just changed this, show me the result" flow. The user who made the change needs to see it. Everyone else can tolerate a brief lag.
Model 4 — Causal Consistency
Causal consistency goes one step further than read-your-writes. It guarantees that operations that are causally related — one event logically depends on another — are seen in the right order by everyone.
Real-world analogy:
You post a question in a forum: "Anyone know how to fix this bug?" Your colleague replies "Yes, use this fix." Without causal consistency, some users might see the reply before the original question — the answer appears before the question it answers. Causal consistency ensures that if you see the reply, you also see the question it was replying to.
Causal consistency in practice — MongoDB sessions:
// MongoDB causal consistency session
// Operations in this session are causally ordered
const session = client.startSession({ causalConsistency: true })
// Write: post a comment
await db.collection('comments').insertOne(
{ post_id: 'p_99', body: 'Great article!', user: 'Priya' },
{ session }
)
// Read: get all comments on this post
// Guaranteed to include the comment just written — causal order preserved
const comments = await db.collection('comments')
.find({ post_id: 'p_99' }, { session })
.toArray()
causalConsistency: true — MongoDB tracks a cluster time token for this session. Each write returns a token. Each subsequent read sends that token — MongoDB guarantees the read happens after the write that produced that token.
Why this matters: Without causal consistency, the read might be routed to a replica that hasn't received the write yet. Your comment would vanish from the page immediately after posting — a confusing and trust-destroying user experience.
The Full Consistency Spectrum
| Model | Guarantee | Latency Cost | Use When | Example |
|---|---|---|---|---|
| Strong (Linearizable) | Every read sees the latest write globally | High — 10–50ms | Wrong data = real harm | Bank balances, stock levels |
| Causal | Related operations seen in correct order | Medium — 5–15ms | Order of events matters | Comments, replies, chat |
| Read-Your-Writes | You always see your own writes | Medium — 3–10ms | UX feels broken without it | Profile updates, settings |
| Eventual | All nodes converge — eventually | Low — 1–3ms | Stale data causes no harm | Like counts, view counters, feeds |
The Same System, Different Models for Different Data
The real skill is not picking one consistency model for your whole system. It's picking the right model for each piece of data based on the actual consequences of staleness.
A real e-commerce platform — 4 data types, 4 consistency choices:
If two users see "3 items left" simultaneously and both buy 2, you oversell. Wrong data here = real fulfilment cost, angry customers. No tolerance for staleness.
You place an order, then immediately check "My Orders." You must see it. Other users seeing a 200ms delay on each other's orders — doesn't matter. Your own write must be visible to you instantly.
A user asks "Does this fit a size 8?" Someone replies "Yes, runs true to size." The reply must always appear after the question — causal order. Seeing an answer before the question breaks the conversation thread.
Showing 4,820 vs 4,821 for 100ms — completely harmless. Running strong consistency writes for every single page view would be a catastrophic waste of database resources. Eventual is the obvious choice.
Teacher's Note
The engineers who get consistency right are the ones who ask one question before choosing a model: "What is the actual consequence if two users see different values for this field for the next 200 milliseconds?" If the answer is "a financial loss, an oversell, or a safety issue" — you need strong consistency. If the answer is "a view count is slightly off" — eventual is fine and you'll save enormous resources by using it. Consistency is not a database setting. It's a business decision.
Practice Questions — You're the Engineer
Scenario:
Scenario:
Scenario:
Quiz — Which Model Fits?
Scenario:
Scenario:
Scenario:
Up Next · Lesson 10
NoSQL Use Cases
Real systems, real companies, real decisions — the exact scenarios where NoSQL is the obvious right choice and the ones where engineers regret it later.