Filter concepts by levelShowing all levels.

MongoDB · Section 24

Sessions

Level
advanced
Read
20 min
Concepts
3

What a logical session actually is — a server-tracked identity for related operations, independent of any one connection, enabling causal consistency — why both multi-document transactions and retryable writes are built on that same session identity, and how session lifetime works: automatic idle cleanup, and the implicit sessions most driver operations already get without any explicit code.

MongoDB overview

What is true here

  1. A logical session is a server-tracked identity for a sequence of operations, decoupled from any one underlying connection.
  2. Sessions enable causal consistency — a later read in the same session can be guaranteed to reflect an earlier write made in it.
  3. A transaction is always scoped to a session, which is where its in-progress state lives between operations.
  4. Retryable writes use the session ID plus an incrementing transaction number to let the server recognize a retried write as the same attempt, not a duplicate.
  5. Most single operations already get an implicit, driver-managed session — explicit startSession()/endSession() is for transactions or causal consistency specifically.

What you will be able to do

  • Explain what a session is, and how it differs from a network connection
  • Explain why a transaction cannot exist without a session
  • Explain how retryable writes use session identity to distinguish a retry from a duplicate
  • Know when explicit session management is needed versus when the driver's implicit session already covers it

What a session is

The logical identity behind a sequence of related operations, and why transactions and retryable writes both depend on it.

Logical sessions

standardadvanced

A logical session is a server-side identity for a sequence of related operations, created by the driver and identified by a session ID. It is not a network connection — the same session can span multiple connections, and a connection can carry operations from different sessions over time.

Think of it as

Think of it as a lightweight, server-tracked "conversation" a client can have with the cluster, separate from the underlying TCP connections doing the actual talking. It exists specifically to give the server something to hang causal ordering, retryability, and transaction state on, none of which a bare connection provides on its own.

text
const session = client.startSession(); /* ...operations passing { session }... */ session.endSession();

What we're doing: Show a session enabling causal consistency: a read that is guaranteed to see a write made just before it, in the same session.

javascript
const session = client.startSession()
await orders.insertOne({ _id: "o1", status: "placed" }, { session })
// Because both operations share a session, this read is guaranteed to see
// the insert above, even if it is routed to a secondary that might
// otherwise still be catching up.
const order = await orders.findOne({ _id: "o1" }, { session })
await session.endSession()
3
Causal consistency is a property of operations sharing a session — it is this session identity, not the connection, that lets the server guarantee ordering here.

Why this works: Without a shared session, a write and a following read have no formal relationship the server can use to guarantee ordering — a session is what turns "these operations happened one after another, from the same logical actor" into something the server can actually reason about and enforce.

Remember: A session is a server-tracked identity for a sequence of operations, independent of any one connection — it is the foundation causal consistency, retryable writes, and transactions are all built on.

See also: sessions for transactions and retryable writes · transaction lifecycle and sessions

Why transactions and retryable writes need a session

standardadvanced

A transaction needs somewhere to hold its in-progress state — its session is that place. Retryable writes need a way for the server to recognize "this is the same logical write being retried, not a second one" — the session ID plus a per-write transaction number is exactly that identity.

Think of it as

Both features solve a version of the same problem: the server needs to recognize related operations as related, across network hiccups and retries, rather than treating each one as an independent, anonymous request. A session is the identity that makes that recognition possible.

text
// A transaction: always session.startTransaction(). A retryable write: session identity + txnNumber, usually handled by the driver automatically.

What we're doing: Show why a retry needs the session-scoped identity to be safe, contrasting it with a plain retry that has none.

javascript
// Retryable write: the driver attaches session + an incrementing transaction
// number to this write. If a network blip happens after the write applied
// but before the ack reaches the client, retrying is recognized as the
// same attempt — not a second insert.
await orders.insertOne(order, { session })

// Without that identity, a naive client-side retry after a timeout cannot
// tell "my write never arrived" apart from "it arrived, but the ack didn't" —
// and retrying blindly risks a duplicate.
5
The session-plus-transaction-number identity is exactly what lets the server recognize a retried write as the same one, rather than a new insert.

Why this works: A network blip after a write applies but before its acknowledgement reaches the client is genuinely ambiguous from the client's point of view — the session-scoped retry identity is what resolves that ambiguity safely, on the server side, instead of leaving the client to guess.

Remember: A transaction needs a session to hold its state between operations; a retryable write needs the session-scoped identity to let the server recognize a retry as the same attempt, not a duplicate.

See also: logical sessions · transaction lifecycle and sessions

Advertisement

Session lifecycle in practice

How long a session lives, and when application code needs to manage one explicitly versus relying on the driver.

Session lifetime and driver management

standardadvanced

An idle session is automatically cleaned up by the server after a timeout (30 minutes by default) if it is never explicitly ended. Most drivers also start an implicit session for any operation that does not have one, so application code often benefits from sessions without ever calling startSession() directly.

Think of it as

Sessions are cheap and mostly invisible by design — explicit session management (startSession/endSession) is something you reach for specifically for transactions or causal consistency, not something every operation needs to manage by hand.

text
// Implicit: db.collection.findOne({...}) already gets an implicit session. Explicit: needed for transactions or causal consistency.

What we're doing: Contrast code that never touches a session explicitly against code that needs one for a transaction.

javascript
// No explicit session — the driver creates an implicit one per operation
await orders.insertOne({ ... })

// Explicit session — required because a transaction needs to hold state
// across multiple operations
const session = client.startSession()
try {
  session.startTransaction()
  await orders.insertOne({ ... }, { session })
  await inventory.updateOne({ ... }, { session })
  await session.commitTransaction()
} finally {
  await session.endSession()
}
2
This single operation already gets retryable-write safety from an implicit session the driver manages entirely on its own.
6
A transaction specifically needs an explicit, shared session across its operations, since that is where the in-progress transaction state actually lives.

Why this works: Most application code never needs to think about sessions at all — the driver's implicit session already provides retryable-write safety for single operations, and explicit session management is worth the extra code specifically when a transaction or causal-consistency guarantee is needed.

Remember: Most single operations already get an implicit session with retryable-write safety for free — reach for explicit startSession()/endSession() specifically for transactions or causal consistency, and always end what you start.

See also: logical sessions · sessions for transactions and retryable writes

Advertisement