MongoDB Transactions & Consistency
Every write to a single MongoDB document is atomic, including updates touching many embedded fields and arrays at once. Because well-designed documents keep related data together, most applications need nothing more. When a change must span multiple documents or collections, such as moving money between accounts or reserving inventory while creating an order, MongoDB supports multi-document ACID transactions across replica sets and sharded clusters.
Transactions are only part of the story. Write concern controls how many replicas must acknowledge a write before it counts as successful. Read concern controls how durable the data you read must be. Read preference decides which members serve reads. Together they set where your application sits between speed and safety.
TL;DR
- Single-document writes are always atomic. Model data to take advantage of it.
- Multi-document transactions provide ACID guarantees across documents, collections, and shards. Use them when you need them, not by default.
- Use the driver's
withTransactionhelper; it retries on transient errors and unknown commit results. - Write concern
majority(the default) means a write survives failover;w: 1can be rolled back. - Read concern (
local,majority,snapshot,linearizable) sets how committed the data you read must be. - Retryable writes and causally consistent sessions smooth over failovers and reading from secondaries.
Quick Example
Transferring credits between two accounts atomically (Node.js driver):
Either all three writes commit or none do. Other clients never see money leave account A without arriving in B.
Core Concepts
Single-Document Atomicity
An updateOne that changes five fields, pushes to an array, and increments a counter on one document either fully applies or doesn't apply at all. Combined with conditional filters ({ balance: { $gte: 100 } }) and operators like $inc, many "transactional" needs are solved with one well-designed document and one update. This is why schema design is the first tool for consistency in MongoDB.
Multi-Document Transactions
Transactions (replica sets since 4.0, sharded clusters since 4.2) give:
- Atomicity: all writes commit or abort together.
- Snapshot isolation: reads inside the transaction see a consistent point-in-time view.
- Durability: with write concern
majority, committed transactions survive primary failover.
Limits and costs: the default maximum runtime is 60 seconds (transactionLifetimeLimitSeconds), large transactions cache a lot of state, and conflicting writes cause write conflicts that abort one transaction. Transactions spanning shards add coordination overhead.
Handling Transient Errors
Transactions can fail with TransientTransactionError (for example a write conflict or failover), which means retry the whole transaction, or UnknownTransactionCommitResult, which means retry the commit. The withTransaction / with_transaction helpers in official drivers implement these retry loops for you. Keep the transaction body free of non-idempotent side effects like sending emails, because it may run more than once.
Write Concern
Read Concern and Read Preference
Read concern decides what data a read may return:
local(default): the node's latest data, which might later be rolled back.majority: only data acknowledged by a majority, so it won't be rolled back.snapshot: a consistent point-in-time view (used by transactions).linearizable: reflects all majority-acknowledged writes before the read began, on the primary only. It's the strongest and slowest.
Read preference decides where reads go: primary (default), primaryPreferred, secondary, secondaryPreferred, or nearest. Reading from secondaries spreads load but may return stale data because of replication lag.
Causal Consistency and Retryable Writes
A causally consistent session guarantees read-your-own-writes and monotonic reads even when reading from secondaries: the driver passes cluster times so a secondary waits until it has caught up. Retryable writes (on by default in modern drivers) automatically retry a write once after a network error or failover, with the server deduplicating so the write isn't applied twice.
Best Practices
Prefer Document Design Over Transactions
If the data changed together can live in one document, such as an order and its line items, you get atomicity without transaction overhead. Reach for transactions for genuinely cross-document invariants: transfers, inventory reservations, uniqueness across collections.
Keep Transactions Short
Do reads and computation before starting the transaction when possible, touch few documents, and never wait on user input or slow external calls inside one. Long transactions hold resources and conflict more.
Use majority for Important Writes
The default write concern majority is the right choice for anything you can't afford to lose. Use w: 1 only for high-volume data where occasional loss on failover is acceptable, such as metrics or logs.
Make Operations Idempotent
Retries at the driver and application level mean an operation can execute more than once. Use unique keys, conditional updates, and idempotency keys for externally triggered writes such as payment webhooks.
Common Mistakes
Side Effects Inside a Retried Transaction
The outbox pattern, writing an "email to send" document inside the transaction for a separate worker to process, gives reliable side effects. See the saga pattern for multi-service workflows.
Forgetting to Pass the Session
Every operation that should be part of the transaction must receive { session }. Operations without it run outside the transaction and commit independently, which is a subtle and dangerous bug.
Reading Your Write From a Secondary
Writing to the primary and immediately reading from a secondary can return the old value. Read from the primary for read-your-writes flows, or use causally consistent sessions.
FAQ
Is MongoDB ACID compliant?
Yes. Single-document operations have always been atomic, and multi-document ACID transactions are supported across replica sets and sharded clusters. With write concern majority and snapshot read concern, transactions provide atomicity, consistency, snapshot isolation, and durability.
Are MongoDB transactions slow?
They cost more than single-document writes, with extra round trips, conflict detection, and more work for cross-shard commits, but they're practical for normal use. Performance problems usually come from long-running transactions, hot documents causing write conflicts, or using transactions for everything instead of relying on document atomicity.
What happens to unacknowledged writes during failover?
Writes acknowledged only by the old primary (w: 1) that hadn't replicated may be rolled back when a new primary is elected, and written to rollback files for manual recovery. Writes acknowledged with majority are preserved.
Do I need transactions with a single-node deployment?
Transactions require a replica set, even a single-member one, because they rely on the oplog. Local development setups often run a one-node replica set for this reason.
Related Topics
- MongoDB — The database overview
- Database Transactions — ACID and isolation levels in general
- MongoDB Schema Design — Using document atomicity instead of transactions
- MongoDB Sharding — Transactions across shards
- Database Replication — Replication lag and read consistency
- Idempotency — Safe retries