Transactions, sessions and read/write concerns
Use sessions for causal consistency, wrap multi-document changes in a transaction correctly, and choose read and write concerns that match what the business can tolerate losing.
Sessions and causal consistency
A session is the context for a sequence of operations. It carries an operation time and a cluster time, which is what lets the driver guarantee that a read following a write on the same session sees that write even when it is served by a different member.
const session = db.getMongo().startSession();
const s = session.getDatabase("shop");
s.orders.insertOne({ customer: "Ada", status: "new" });
s.orders.findOne({ customer: "Ada" }); // sees the insert above
session.endSession();
// causal consistency is on by default; this makes it explicit
const causal = db.getMongo().startSession({ causalConsistency: true });- Causal consistency is about ordering within one session, not about global freshness. Two sessions can still observe events in different orders.
- Sessions are also the mechanism behind retryable writes: the server tracks the transaction number so a retried write is not applied twice.
- Always end a session. An abandoned session pins its server-side state until the timeout expires.
Multi-document transactions
const session = db.getMongo().startSession();
const shop = session.getDatabase("shop");
session.startTransaction({
readConcern: { level: "snapshot" },
writeConcern: { w: "majority" },
readPreference: "primary"
});
try {
shop.orders.updateOne({ _id: orderId }, { $set: { status: "paid" } });
shop.inventory.updateOne({ sku: "LAMP-01" }, { $inc: { onHand: -1 } });
session.commitTransaction();
} catch (err) {
session.abortTransaction();
throw err;
} finally {
session.endSession();
}- Transactions require a replica set or a sharded cluster. A standalone server does not support them, which is one more reason to develop against the same topology you deploy.
- A transaction is limited to 60 seconds by
transactionLifetimeLimitSecondsand to 16 MB of oplog. Never wait on an external API or a user response inside one. - All operations in the transaction must use the same session. An operation that omits it runs outside the transaction and is not rolled back.
- Reads inside a transaction use
snapshotread concern, and writes take document-level locks that other transactions must wait for.
Read and write concerns
| Setting | Meaning |
|---|---|
w: 1 | Acknowledged by the primary's memory only |
w: "majority" | Replicated to a majority; survives an election |
w: 0 | Fire and forget; no acknowledgement, no error on failure |
j: true | Acknowledged after the journal write, so a crash does not lose it |
readConcern: local | Whatever the node has, including writes that a failover could roll back |
readConcern: majority | Only data that a majority has acknowledged and cannot be rolled back |
readConcern: snapshot | A consistent point-in-time view; required inside transactions |
readPreference | Which member is eligible to serve a read |
The two settings are independent and both matter. Writing with w: "majority" and then reading with readConcern: local from a secondary can still return an older value, because the read is served by a member that may not have applied the write yet.
w: 0 is much faster and much more dangerous: the driver reports success without knowing whether any node received the write, so a failure is invisible and a failover can erase it. Reserve it for telemetry you can genuinely afford to lose.FAQ
Do I need transactions?
Why did my transaction fail after a minute?
transactionLifetimeLimitSeconds. The server aborts a transaction that runs or idles too long, because it pins a snapshot and holds locks the whole time. Keep transactions short and never perform external calls inside one.Related
Documents, collections and queries Drivers and ODMs in application code
Last refreshed 2026-09-18.