Backup and Restore (mongodump/mongorestore)
Backups exist for one reason: to undo disasters, whether that’s a dropped collection, a bad deploy that corrupted data, or a full server loss. MongoDB ships two command-line tools for this: mongodump, which reads documents from a live database and writes them to BSON files, and mongorestore, which reads those BSON files back into a database. Together they give you a logical backup — a full copy of your data and index definitions that can be restored into any MongoDB deployment, even one running a different server version or topology than the original.
Overview: How It Works
mongodump and mongorestore are separate executables that ship alongside mongosh in the MongoDB Database Tools package — they are run from your operating system shell, not typed inside the mongosh REPL. mongodump connects to a mongod or mongos process the same way any client does, runs a query against each collection in scope, and streams the resulting documents to disk as BSON — the same binary format MongoDB stores documents in internally. Because it writes BSON rather than JSON, a dump preserves exact types: an ObjectId stays an ObjectId, a Date stays a Date, a NumberLong stays a NumberLong, instead of collapsing into strings the way a naive JSON export would. Alongside each collection’s .bson file, mongodump also writes a .metadata.json file recording that collection’s index definitions, collation, and validation rules, so mongorestore can rebuild indexes instead of just reinserting raw documents into an unindexed collection.
This is what "logical backup" means: it’s built from the documents themselves via the normal query engine, as opposed to a physical backup, which copies the raw on-disk data files (or a storage-layer snapshot) while the server is stopped or in a special backup mode. Logical backups are portable across MongoDB versions and even between a standalone, a replica set, and a sharded cluster; physical backups are faster to take and restore but are tied to the exact storage engine and server version that produced them. For a small-to-medium database, mongodump/mongorestore is usually the right tool. For a multi-terabyte production cluster, the restore time of a logical backup — which has to reinsert every document and rebuild every index from scratch — can become impractical, and teams instead lean on filesystem/volume snapshots or a managed continuous-backup service such as Atlas’s.
By default, a multi-collection dump does not guarantee a single, database-wide instant in time on a busy server, because dumping one collection after another takes time and writes keep happening in between. Against a replica set, the --oplog flag fixes this: mongodump also records the oplog entries generated while the dump ran, and mongorestore --oplogReplay replays them, so the restored data reflects the exact moment the dump started rather than the moment each collection happened to finish. Always pair these two flags when backing up a replica set under active writes.
Syntax
mongodump --uri="<connection-string>" [--db=<database>] [--collection=<collection>] [--query='<json-filter>'] [--out=<path>] [--gzip] [--archive=<file>] [--oplog]
mongorestore --uri="<connection-string>" [--drop] [--gzip] [--archive=<file>] [--nsInclude=<namespace>] [--nsFrom=<old> --nsTo=<new>] [--oplogReplay] <dump-directory>
| Flag (mongodump) | Meaning |
|---|---|
--uri |
Full connection string, including credentials and target database. |
--db |
Limit the dump to a single database instead of every database the user can read. |
--collection |
Limit the dump to a single collection (requires --db). |
--query |
A JSON filter document; only matching documents are dumped. |
--out |
Directory to write the dump into (default ./dump). |
--gzip |
Compress each output file with gzip. |
--archive |
Write everything to a single file (or stdout) instead of a directory tree. |
--oplog |
Also capture oplog entries during the dump for point-in-time consistency. |
| Flag (mongorestore) | Meaning |
|---|---|
--uri |
Connection string for the restore target. |
--drop |
Drop each target collection immediately before restoring it. |
--gzip / --archive |
Read a gzip-compressed dump / a single archive file, matching how it was dumped. |
--nsInclude |
Restore only namespaces matching a pattern, e.g. ecommerce.orders. |
--nsFrom / --nsTo |
Rename a namespace during restore (e.g. into a different database). |
--oplogReplay |
Replay the captured oplog entries after loading the data (requires a dump taken with --oplog). |
Examples
Example 1: Full database dump and restore into a new database
First, seed a small orders collection so there’s something to back up:
use ecommerce
db.orders.insertMany([
{ customer: "Amit Shah", status: "shipped", total: 2499, items: [{ sku: "SKU-100", qty: 1 }], createdAt: new Date("2026-07-01") },
{ customer: "Priya Rao", status: "pending", total: 799, items: [{ sku: "SKU-204", qty: 2 }], createdAt: new Date("2026-07-15") },
{ customer: "Devika Nair", status: "shipped", total: 5199, items: [{ sku: "SKU-310", qty: 1 }], createdAt: new Date("2026-07-20") }
]);
db.orders.createIndex({ status: 1 });
Output:
{
acknowledged: true,
insertedIds: {
'0': ObjectId('66b1f2a1c9e77a001f3d1a01'),
'1': ObjectId('66b1f2a1c9e77a001f3d1a02'),
'2': ObjectId('66b1f2a1c9e77a001f3d1a03')
}
}
status_1
Now dump the whole database from a terminal (not mongosh):
mongodump --uri="mongodb://<user>:<password>@<cluster-url>/ecommerce" --out=./backups/2026-08-04
Output:
2026-08-04T10:15:02.114+0000 writing ecommerce.orders to backups/2026-08-04/ecommerce/orders.bson
2026-08-04T10:15:02.140+0000 done dumping ecommerce.orders (3 documents)
Restore into a differently named database, to prove the dump is a complete, portable copy rather than something tied to the original database name:
mongorestore --uri="mongodb://<user>:<password>@<cluster-url>/" --nsFrom="ecommerce.*" --nsTo="ecommerce_restored.*" ./backups/2026-08-04
Output:
2026-08-04T10:22:11.203+0000 3 document(s) restored successfully. 0 document(s) failed to restore.
Back in mongosh, confirm the restored data landed where expected:
db.getSiblingDB("ecommerce_restored").orders.countDocuments();
Output:
3
The .metadata.json file also carried over the status_1 index definition, so the restored collection has it too — nothing about the dump/restore round-trip lost the schema information, even though it moved to a brand-new database.
Example 2: Dumping a single collection with a filter
Dumping an entire large collection when you only need recent, "hot" documents wastes time and disk. --query filters what gets dumped, just like a normal find() filter:
mongodump --uri="mongodb://<user>:<password>@<cluster-url>/" --db=ecommerce --collection=orders --query='{ "status": "shipped" }' --out=./backups/shipped-only
Output:
2026-08-04T10:31:44.902+0000 done dumping ecommerce.orders (2 documents)
Only the two shipped orders were written out, even though the collection has three documents total — the pending order was excluded by the filter, exactly as it would be by an equivalent db.orders.find({ status: "shipped" }) in mongosh.
Example 3: Compressed single-file archive between two clusters
For moving data between environments without leaving loose files scattered on disk, combine --gzip with --archive to produce one compressed file:
mongodump --uri="mongodb://<user>:<password>@<source-cluster-url>/ecommerce" --gzip --archive=ecommerce.gz.archive
mongorestore --uri="mongodb://<user>:<password>@<target-cluster-url>/" --gzip --archive=ecommerce.gz.archive --drop
The --drop flag here makes the restore idempotent: rerunning it after a failed first attempt drops and re-creates each collection cleanly instead of colliding with partially restored data.
How It Works Step by Step
mongodump first authenticates and negotiates a connection using the URI. Then, for each collection in scope, it opens a cursor with a query (empty by default, meaning "all documents") and reads results in batches, writing each batch straight to that collection’s BSON file as it arrives — memory use stays low even for a huge collection because nothing has to be buffered in full. It also issues a listIndexes command per collection and writes the results into the metadata file. When --oplog is set, mongodump additionally tails the replica set’s oplog for the duration of the dump and stores those operations in a special oplog.bson file.
On restore, mongorestore re-creates each target collection if it doesn’t exist, inserts the documents from each BSON file in batches (functionally like repeated insertMany calls), and only then builds the indexes recorded in the metadata file. Building an index once against an already-loaded collection is far cheaper than maintaining it incrementally on every single insert, which is why index creation happens last, not first. If --oplogReplay was requested, the captured oplog operations are replayed last of all, bringing the restored data forward to the exact moment the original dump finished.
Common Mistakes
Mistake 1: Restoring without --drop onto non-empty collections
mongorestore never deletes anything by default. If the target collection already has documents sharing an _id with the dump, every conflicting insert fails:
mongorestore --uri="mongodb://<user>:<password>@<cluster-url>/" ./backups/2026-08-04
Output:
Failed: ecommerce.orders: error restoring from backups/2026-08-04/ecommerce/orders.bson: E11000 duplicate key error collection: ecommerce.orders index: _id_ dup key: { _id: ObjectId('66b1f2a1c9e77a001f3d1a01') }
The fix is to explicitly drop each target collection before loading the dump into it:
mongorestore --uri="mongodb://<user>:<password>@<cluster-url>/" --drop ./backups/2026-08-04
Mistake 2: Backing up a busy replica set without --oplog
A multi-collection dump taken without --oplog is not a single point-in-time snapshot; each collection finishes at a slightly different moment, so cross-collection consistency can silently break under active writes:
mongodump --uri="mongodb://<user>:<password>@<cluster-url>/ecommerce" --out=./backups/inconsistent
Add --oplog on the dump and --oplogReplay on the restore so the result reflects one consistent instant:
mongodump --uri="mongodb://<user>:<password>@<cluster-url>/ecommerce" --oplog --out=./backups/consistent
mongorestore --uri="mongodb://<user>:<password>@<cluster-url>/" --oplogReplay ./backups/consistent
Mistake 3: Backing up with an under-privileged user
mongodump does not fail loudly when it can’t read a collection — it simply dumps whatever the connecting user is authorized to see, so a partial backup can look identical to a complete one on the day it’s created. Use a dedicated backup role with explicit read access to every database you intend to back up, and periodically restore into a scratch database to confirm nothing was silently skipped.
Best Practices
- Use
--uriwith a full connection string rather than separate--host/--port/auth flags — it matches how an application actually connects and is less error-prone. - Always pair
--oplogon the dump with--oplogReplayon the restore for a replica set under active write load. - Compress with
--gzip, or write a single file with--archive, to cut disk usage and simplify moving backups around. - Periodically restore into a scratch database or throwaway container — a backup you’ve never restored is not a backup you can trust.
- Store dumps somewhere other than the database server itself, and encrypt them at rest, since a BSON dump has no built-in encryption.
- Grant the backup account a dedicated, minimally scoped read role instead of reusing an administrative account.
- Past a few hundred gigabytes, evaluate filesystem/volume snapshots or a managed continuous-backup service instead of relying solely on
mongodump.
Practice Exercises
- Create a test database with two collections and a few dozen documents each. Take a full, gzip-compressed dump, restore it into a new empty database, and confirm the document counts and at least one index on each collection match the originals.
- Dump only the documents in an
orderscollection wherestatusequals"shipped", using--query, and confirm the restored collection contains only those documents. - Restore a dump on top of a target database that already has conflicting documents, without
--drop. Observe the duplicate key errors, then rerun with--dropand confirm it succeeds cleanly.
Summary
mongodumpandmongorestoreare separate command-line tools, not mongosh commands, that create and restore logical, BSON-based backups of data and indexes.- BSON preserves exact types (
ObjectId,Date,NumberLong) that a plain JSON export would lose. --oplogon the dump plus--oplogReplayon the restore is required for a point-in-time-consistent backup of a replica set under active writes.mongorestorenever deletes existing data unless you pass--drop, so restoring without it against a non-empty target produces duplicate key errors and a silently incomplete restore.- Backups should use a minimally scoped role, be stored off the database server, and be test-restored periodically.
- For very large deployments, logical dumps give way to filesystem snapshots or managed continuous-backup services.
