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
2. MongoDB Architecture đī¸
At a high level, MongoDB's architecture separates concerns into distinct layers, each responsible for a specific part of data handling.
Reference
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.
| Engine | Status |
|---|---|
| WiredTiger | Default, actively developed |
| In-Memory | Enterprise-only, for volatile ultra-low-latency use cases |
| MMAPv1 | Deprecated, 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.
- 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
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.
| Feature | JSON | BSON |
|---|---|---|
| Type richness | Limited (string, number, bool, null) | Rich (Date, ObjectId, Binary, Decimal128) |
| Traversal speed | Requires full parse | Length-prefixed fields allow fast skipping |
| Size | Smaller (text) | Slightly larger (binary overhead) |
Reference
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
8. Index Internals đ
MongoDB indexes are implemented as B-Trees, mapping indexed field values to the location of the corresponding document.
- 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
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
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.
- 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
14. Sharding Internals đ§Š
Sharding distributes data horizontally across multiple shards (each typically a replica set), coordinated by mongos routers and config servers.
- 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
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
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.
Important
18. Locking Mechanism đ
MongoDB uses a multi-granularity lockingsystem â global, database, collection, and (within WiredTiger) document-level â to balance concurrency with consistency.
| Lock Level | Scope |
|---|---|
| Global | Rare, used for certain administrative commands |
| Database | Intent locks per database |
| Collection | Intent locks per collection |
| Document | Fine-grained, handled internally by WiredTiger's MVCC |
Note
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
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
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
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 đĢ
| Misconception | Reality |
|---|---|
| "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
25. Frequently Asked Questions â
Question
Answer
Question
Answer
Question
Answer
26. Summary đ
Summary
- Official Docs: WiredTiger Storage Engine
- Replication: MongoDB Replication Documentation