Why MongoDB Added Multi-Document Transactions
Every single-document write in MongoDB has always been atomic, but many real-world operations touch multiple documents or collections that must succeed or fail together, such as transferring funds between two account documents or updating an order and decrementing inventory. MongoDB 4.0 introduced multi-document ACID transactions for replica sets, and 4.2 extended them to sharded clusters, letting you wrap a sequence of reads and writes so that either all of them commit or none do.
Cricket analogy: Like a run-out review where both the batsman's dismissal and the fielding side's catch must be confirmed together or the whole review is voided, a transaction ensures a fund transfer's debit and credit both commit or neither does.
Using Transactions with Sessions
Transactions in MongoDB run within a client session, and the driver exposes a withTransaction() helper that automatically retries the transaction on certain transient errors like TransientTransactionError or write conflicts, which is the recommended approach over manually calling startTransaction, commitTransaction, and abortTransaction. Because a transaction holds locks and consumes resources on every shard it touches, keeping the operations inside it minimal and fast is essential to avoid contention with other concurrent writes.
Cricket analogy: Like a DRS review having an automatic retry protocol if the first replay angle is inconclusive, withTransaction automatically retries a transaction if it hits a transient conflict, rather than making the developer handle it manually.
const session = client.startSession();
try {
await session.withTransaction(async () => {
const accounts = client.db("bank").collection("accounts");
await accounts.updateOne(
{ _id: "acct-A" },
{ $inc: { balance: -100 } },
{ session }
);
await accounts.updateOne(
{ _id: "acct-B" },
{ $inc: { balance: 100 } },
{ session }
);
}, {
readConcern: { level: "snapshot" },
writeConcern: { w: "majority" }
});
} finally {
await session.endSession();
}Not every atomicity need requires a transaction. A single updateOne() with operators like $set, $inc, and array update operators is already atomic on one document, and schema designs that embed related data into one document often avoid the need for a transaction entirely.
Transaction Limits and Performance Considerations
By default, MongoDB aborts a transaction that runs longer than 60 seconds (transactionLifetimeLimitSeconds) to release locks and prevent it from blocking other operations, and transactions also hold WiredTiger snapshot resources that can grow cache pressure if too many run concurrently. As a result, transactions work best for short, targeted operations touching a handful of documents; bulk operations spanning thousands of documents should generally be redesigned as smaller batches or restructured to avoid needing a transaction at all.
Cricket analogy: Like a rain-delay rule that abandons a match if play can't resume within a set window to protect the tournament schedule, MongoDB aborts transactions running longer than 60 seconds to protect cluster resources.
Running many long or large transactions concurrently increases WiredTiger cache pressure because each transaction holds a snapshot of the data. In write-heavy clusters this can cause cache eviction stalls that slow down unrelated operations, so batch large bulk changes outside of transactions where full atomicity across the whole batch isn't strictly required.
Read Concern and Isolation
Transactions use snapshot read concern by default, meaning all reads within the transaction see a consistent snapshot of data as of the transaction's start, isolated from concurrent writes happening outside it, and a commit with write concern majority ensures the change is durable before the application considers it complete. Combining readConcern 'snapshot' with writeConcern 'majority' gives you MongoDB's strongest consistency guarantee, sometimes called 'read your own writes' plus cross-shard atomicity for sharded transactions.
Cricket analogy: Like a scorecard frozen at the moment a review starts so later events don't change what the umpires are judging, snapshot read concern gives a transaction a consistent view unaffected by concurrent writes.
- Single-document writes are always atomic; multi-document transactions were added in MongoDB 4.0 (replica sets) and 4.2 (sharded clusters).
- withTransaction() is the recommended API since it automatically retries on transient errors.
- Transactions default to a 60-second lifetime limit and abort past it to release resources.
- Keep transactions short and targeted; redesign bulk operations to avoid huge transactions.
- Snapshot read concern gives a transaction a consistent, isolated view of the data as of its start.
- Combining snapshot read concern with majority write concern gives MongoDB's strongest consistency guarantee.
- Consider embedding related data in one document first, since single-document atomicity often avoids needing a transaction.
Practice what you learned
1. What is the recommended way to run a transaction in MongoDB drivers?
2. What is the default maximum lifetime of a MongoDB transaction?
3. What read concern do transactions use by default?
4. Why were single-document operations already sufficient before multi-document transactions existed?
5. What is a key performance consideration when using transactions?
Was this page helpful?
You May Also Like
Replica Sets Explained
How MongoDB replica sets provide high availability through automatic failover, elections, and data redundancy across primary and secondary nodes.
Sharding in MongoDB
How MongoDB distributes data across multiple shards using shard keys, chunks, and a query router to scale horizontally beyond a single server's capacity.
MongoDB Interview Questions
A curated set of commonly asked MongoDB interview questions and concepts, covering data modeling, indexing, replication, and sharding fundamentals.