MongoDB Internals: The Complete Guide 🧠

1. Introduction 🌱

Understanding how MongoDB works under the hood— its storage engine, query planner, replication protocol, and concurrency model — transforms how you design schemas, write queries, and diagnose production issues.

This tutorial explores MongoDB's internal architecture: from how a single document is stored on disk, to how a cluster coordinates replication and sharding across many nodes.

Information

This is an advanced tutorial. Familiarity with basic MongoDB usage (CRUD, indexes, replica sets) is assumed throughout.

2. MongoDB Architecture đŸ›ī¸

At a high level, MongoDB's architecture separates concerns into distinct layers, each responsible for a specific part of data handling.

MongoDB Server (mongod)
Query Layer (parsing, planning, execution)
Replication Layer
Storage Engine (WiredTiger)
Oplog
Election Protocol
B-Tree Indexes
Document Storage (BSON)

Reference

A mongos router sits above this stack in sharded deployments, routing queries to the correct shard(s) without storing data itself.

3. Storage Engine đŸ—„ī¸

The storage engine is the component responsible for how data is actually written to and read from disk. It is pluggable, though WiredTiger has been the default since MongoDB 3.2.

EngineStatus
WiredTigerDefault, actively developed
In-MemoryEnterprise-only, for volatile ultra-low-latency use cases
MMAPv1Deprecated, removed in MongoDB 4.2+

4. WiredTiger đŸŒŗ

WiredTiger uses a LSM-like or B-Tree based structure with multi-version concurrency control (MVCC), allowing readers and writers to operate without blocking each other in most cases.

WiredTiger Engine
In-Memory Cache (working set)
Checkpoints (periodic durable snapshots)
Write-Ahead Log (journal)
  • Data is compressed on disk using snappy by default.
  • WiredTiger takes a checkpoint every 60 seconds by default, flushing a consistent view of data to disk.
  • MVCC lets readers see a consistent snapshot even while writes are in progress.

Important

Between checkpoints, durability is guaranteed by the journal(see Section 17) — not by the checkpoint itself.

5. BSON Internals đŸ“Ļ

BSON (Binary JSON) is MongoDB's native document format — a binary-encoded serialization that supports richer types than plain JSON, such as Date, ObjectId, and Int64.

FeatureJSONBSON
Type richnessLimited (string, number, bool, null)Rich (Date, ObjectId, Binary, Decimal128)
Traversal speedRequires full parseLength-prefixed fields allow fast skipping
SizeSmaller (text)Slightly larger (binary overhead)

Reference

Every BSON document is limited to 16MB, a constraint designed to prevent any single document from monopolizing RAM or network bandwidth.

6. Document Storage 📄

Within WiredTiger, documents are stored in collections, which are internally organized as B-Trees keyed by _id or a synthetic record identifier.

  • Documents are stored in compressed form on disk and decompressed into memory when accessed.
  • Updates that keep a document's size similar are more efficient than updates causing significant growth (which may trigger relocation).
  • Padding and pre-allocation strategies from older engines (like MMAPv1) are no longer relevant with WiredTiger's dynamic allocation.

7. Collection Storage đŸ—‚ī¸

Each collection maps to its own WiredTiger table internally, alongside separate tables for each of its indexes.

collection-stats.js

const stats = await db.collection('orders').stats();
console.log('Storage size:', stats.storageSize);
console.log('Total index size:', stats.totalIndexSize);
console.log('Average doc size:', stats.avgObjSize);

Note

Capped collections — fixed-size collections that overwrite the oldest documents — are used internally for the oplog itself (see Section 13).

8. Index Internals 📇

MongoDB indexes are implemented as B-Trees, mapping indexed field values to the location of the corresponding document.

B-Tree Index Root
Internal Node
Internal Node
Leaf: value → document location
Leaf: value → document location
Leaf: value → document location
  • The default _id index is created automatically and cannot be dropped.
  • Compound indexes store keys in the order fields are declared, which determines which query patterns they can serve efficiently.
  • Indexes are updated synchronouslyon every write — this is the source of index-related write overhead.

9. Query Execution Engine âš™ī¸

When a query runs, MongoDB's execution engine processes it through a tree of execution stages, each responsible for a specific operation like scanning, filtering, or sorting.

execution-stages.js

const plan = await db.collection('orders')
  .find({ status: 'pending' })
  .sort({ createdAt: -1 })
  .explain('executionStats');

console.log(plan.executionStats.executionStages.stage); // e.g. "SORT" -> "IXSCAN" -> "FETCH"
  • COLLSCAN— scans every document in the collection.
  • IXSCAN— scans an index rather than raw documents.
  • FETCH— retrieves the full document after an index match.
  • SORT— performs an in-memory sort when no index satisfies the requested order.

10. Query Planner 🧭

Before execution, the query planner evaluates multiple candidate index strategies (called plans), runs a brief competition between them, and caches the winner.

Tip

The plan cache can be inspected and cleared with db.collection.getPlanCache()— useful when diagnosing a sudden, unexplained performance regression.

11. Aggregation Engine 🧮

The aggregation framework compiles a pipeline into an internal execution plan, and where possible, pushes early stages down to use available indexes.

aggregation-explain.js

const plan = await db.collection('orders').aggregate([
  { $match: { status: 'completed' } },
  { $group: { _id: '$customerId', total: { $sum: '$amount' } } },
]).explain();

console.log(JSON.stringify(plan.stages, null, 2));

Important

MongoDB attempts to reorder and optimize pipeline stages internally — e.g., moving a compatible $matchearlier — but this optimization has limits, so writing efficient pipelines still matters.

12. Replication Internals 🔁

A replica set maintains multiple copies of the same data, with one primary node accepting writes and secondary nodes replicating changes asynchronously.

Primary (accepts writes)
Secondary 1 (replicates oplog)
Secondary 2 (replicates oplog)
  • Secondaries continuously tail the primary's oplog and apply the same operations locally.
  • An election occurs automatically if the primary becomes unreachable, promoting a new primary from eligible secondaries.
  • Write concern (e.g., w: 'majority') determines how many nodes must acknowledge a write before it's considered successful.

13. Oplog 📜

The oplog (operations log) is a special capped collection recording every write operation in an idempotent form, enabling both replication and change streams.

oplog-example.js

// Simplified representation of an oplog entry
{
  ts: Timestamp(1690000000, 1),
  op: 'u',           // update operation
  ns: 'shopDB.orders',
  o: { $set: { status: 'shipped' } },
  o2: { _id: ObjectId('...') },
}

Note

The oplog is a capped collection— older entries are automatically overwritten once it reaches its configured size, which limits how far back point-in-time recovery can reach without a supplementary snapshot.

14. Sharding Internals 🧩

Sharding distributes data horizontally across multiple shards (each typically a replica set), coordinated by mongos routers and config servers.

mongos Router
Config Servers (metadata: shard key ranges, chunk locations)
Shard 1 (replica set)
Shard 2 (replica set)
  • The shard key determines how documents are distributed across shards.
  • Config serversstore cluster metadata — they themselves run as a dedicated replica set.
  • mongos routes each query to the relevant shard(s) based on the shard key, avoiding a full cluster-wide scan when possible.

15. Chunk Management 🧱

Within a sharded collection, data is divided into chunks — contiguous ranges of shard key values — which the balancer redistributes across shards to keep load even.

chunk-distribution.js

const chunks = await db.getSiblingDB('config').chunks
  .find({ ns: 'shopDB.orders' })
  .toArray();

console.log('Total chunks:', chunks.length);

Warning

A poorly chosen shard key can produce jumbo chunks— oversized chunks the balancer cannot split or migrate — leading to persistent load imbalance.

16. Memory Management 🧠

WiredTiger maintains an internal cache (by default around 50% of available RAM minus 1GB) holding frequently accessed pages of data and index B-Trees.

cache-config.js

// mongod.conf
storage:
  wiredTiger:
    engineConfig:
      cacheSizeGB: 4
  • When the working set exceeds cache size, pages must be read from disk, increasing latency.
  • The OS filesystem cache also holds compressed pages, providing a secondary caching layer beneath WiredTiger's own cache.

Tip

Monitor serverStatus().wiredTiger.cache metrics like "pages read into cache" to detect memory pressure before it becomes a production issue.

17. Journaling 📓

The journal is a write-ahead log that records operations before they're applied to the in-memory cache, ensuring durability across unexpected crashes between checkpoints.

Write Operation
Journal (write-ahead log, synced ~every 100ms)
In-Memory Cache
Checkpoint (durable snapshot, ~every 60s)

Important

On an unclean shutdown, MongoDB replays the journal from the last checkpoint to recover any writes that hadn't yet been checkpointed to disk.

18. Locking Mechanism 🔒

MongoDB uses a multi-granularity lockingsystem — global, database, collection, and (within WiredTiger) document-level — to balance concurrency with consistency.

Lock LevelScope
GlobalRare, used for certain administrative commands
DatabaseIntent locks per database
CollectionIntent locks per collection
DocumentFine-grained, handled internally by WiredTiger's MVCC

Note

Most modern write operations only require a brief document-level lockinternally — true collection-wide locking is rare in typical CRUD workloads.

19. Concurrency Control 🔀

WiredTiger's MVCC model allows multiple transactions to operate on independent snapshots of data, avoiding traditional reader-writer contention.

  • Readers see a consistent snapshot as of the start of their operation, unaffected by concurrent in-flight writes.
  • Write conflictsoccur when two transactions attempt to modify the same document concurrently — one is retried automatically.

write-conflict-retry.js

// The driver automatically retries transient write conflicts
// when retryWrites=true is set in the connection string (default since MongoDB 4.2 drivers)

20. Transactions Internals 🔐

Multi-document transactions build on the same MVCC snapshot mechanism, coordinating across the oplog to ensure atomicity across multiple operations and even multiple shards.

Caution

Long-running transactions hold resources (snapshots, locks) for their entire duration — MongoDB enforces a default transaction time limit to bound this cost.

21. Change Streams Internals 📡

Change streams are implemented as a filtered, resumable view over the oplog, exposed through a change-stream-specific aggregation stage internally.

resume-token.js

const changeStream = collection.watch();

changeStream.on('change', (change) => {
  console.log('Resume token:', change._id);
});

// Resuming from a specific point after a disconnect
const resumedStream = collection.watch([], { resumeAfter: savedResumeToken });

Important

The resume tokenencodes a position in the oplog — if the oplog has rolled past that position before resumption, the resume will fail, which is why oplog size and retention matter for change-stream-heavy applications.

22. Performance Internals ⚡

  • Working set in RAMis the single biggest factor in read performance — disk I/O is orders of magnitude slower.
  • Index selectivity (how much an index narrows down candidate documents) directly determines IXSCAN efficiency.
  • Checkpoint frequency affects the tradeoff between recovery time and steady-state write overhead.

Reference

The db.serverStatus()command exposes deep internals — cache statistics, lock timing, and operation counters — useful for advanced performance diagnostics.

23. Best Practices ✅

  • Design indexes with an understanding of how the B-Tree structure serves equality, sort, and range queries.
  • Choose shard keys with awareness of how chunk distribution and the balancer actually operate.
  • Monitor cache and working set metrics proactively rather than reactively during an incident.
  • Understand that durability comes from the journal, not just periodic checkpoints.

24. Common Misconceptions đŸšĢ

MisconceptionReality
"MongoDB has no schema at all"Documents are schema-flexible, but validators and application logic still enforce structure
"Every write locks the whole collection"Modern WiredTiger locking is fine-grained, largely at the document level
"The oplog stores full document snapshots"It stores idempotent operation descriptions, not full before/after documents by default
"More indexes always improve performance"Each index adds write overhead and consumes cache memory

Caution

Assuming MongoDB has no locking at all leads to underestimating contention in write-heavy workloads on a single hot document.

25. Frequently Asked Questions ❓

Question

Does MongoDB support ACID transactions?

Answer

Yes — since MongoDB 4.0 (single replica set) and 4.2 (sharded clusters), multi-document transactions provide full ACID guarantees.

Question

How does MongoDB decide which index to use?

Answer

The query planner runs a brief competition between candidate index plans and caches the winner for future queries with the same shape.

Question

What happens if the oplog is too small?

Answer

A small oplog reduces how far back secondaries can catch up after downtime and how far change streamscan resume from — both can fail if the oplog has rolled past the needed point.

26. Summary 📝

Summary

You've explored MongoDB's internal architecture — from BSON and WiredTiger storage, to index B-Trees, query planning, replication via the oplog, sharding and chunk distribution, and the concurrency and durability mechanisms that tie it all together.
>>To truly optimize a database, you must understand not just what it does, but how it does it.