This chapter follows Replica sets in MongoDB. Multi-document transactions require a replica set or sharded cluster—not a standalone mongod for production patterns.
Single-document atomicity
Updates to one document—including embedded arrays—are atomic at the document level. Many workflows never need a transaction if you model related data in one document (see Schema design).
Sessions and withTransaction
The driver manages retries for transient errors when you use withTransaction:
import { ClientSession, MongoClient } from 'mongodb';
export async function transferFunds( client: MongoClient, fromId: string, toId: string, amount: number,) { const session = client.startSession(); try { await session.withTransaction(async () => { const accounts = client.db('bank').collection('accounts'); const from = await accounts.findOne({ _id: fromId }, { session }); if (!from || from.balance < amount) { throw new Error('Insufficient funds'); } await accounts.updateOne( { _id: fromId }, { $inc: { balance: -amount } }, { session }, ); await accounts.updateOne( { _id: toId }, { $inc: { balance: amount } }, { session }, ); }); } finally { await session.endSession(); }}Pass the same session to every operation inside the transaction.
Read and write concern in transactions
Use snapshot reads (readConcern: 'snapshot') inside transactions for consistent reads of committed data. Default write concern majority ensures durability across the replica set. Long-running transactions increase oplog pressure—keep them short.
Limits and when to avoid transactions
- Maximum transaction duration (60 seconds by default on server—lower in practice).
- Document size and lock contention still apply.
- Prefer idempotent updates and embedding when you can avoid coordinating two collections.
Transactions are a safety net, not a substitute for thoughtful schema design.
Next: Full-text search in MongoDB.