Backups, import/export & GridFS

This section documents the current MongoDB 8.x server line as published at the MongoDB Server Manual, which is the reference these pages are written and verified against. No specific patch version is pinned. Some capabilities (Atlas Search, Atlas Vector Search, and parts of encryption and backup) are Atlas-only — they are linked, not documented in depth.

This content was generated with the assistance of AI and should be verified against the official manual before being relied on in production, since MongoDB iterates quickly.

This section’s bibliography lists the reference material consulted while preparing these pages.

There are three ways to back a MongoDB deployment up, they trade off differently, and none of them is the right answer everywhere. This page compares them, then covers moving data as JSON/CSV and storing files larger than the 16 MB document limit with GridFS.

Backup methods and their trade-offs

mongodump / mongorestore

mongodump writes every document as BSON into a directory tree (one .bson file per collection plus .metadata.json for options and indexes); mongorestore reads it back. It is simple, portable, and needs no coordination with the filesystem, which makes it a fine fit for small deployments and for copying one database into another environment.

Its costs scale badly: it reads all data through the server (competing with live traffic and churning the WiredTiger cache), and a restore has to rebuild every index afterwards. On a large data set both take hours. Add --oplog on a replica-set member so the dump captures the oplog window it spans and restores to a consistent point in time.

# Consistent dump of a whole replica-set member, gzipped, with the oplog tail.
mongodump --uri "mongodb://user:pass@rs1.example.com:27017/?replicaSet=rs0" \
          --oplog --gzip --out /backups/2026-08-30

# Restore into a fresh deployment, replaying the captured oplog.
mongorestore --uri "mongodb://user:pass@new.example.com:27017" \
             --gzip --oplogReplay /backups/2026-08-30

# Single collection, no indexes rebuilt on restore beyond _id.
mongodump --db shop --collection orders --gzip --out /backups/orders

Filesystem / volume snapshots

A block-level snapshot (LVM, or a cloud provider’s EBS/persistent-disk snapshot) captures the data volume almost instantly and independently of data size, which makes it the standard method above a few tens of GB. It gives a point-in-time image if the snapshot is atomic across the whole volume.

The condition that matters: the journal must be on the same volume as the data files, so the snapshot captures a recoverable state. If data and journal live on separate volumes, you need a coordinated snapshot of both, or you must stop writes (or fsync with lock) while the snapshot is taken. Encrypted-storage and --directoryperdb layouts have extra caveats in the manual.

# LVM example: data + journal on the same logical volume.
mongosh --eval 'db.fsyncLock()'                 # flush and block writes (optional if snapshot is atomic)
lvcreate --snapshot --size 20G --name mongo_snap /dev/vg0/mongo_data
mongosh --eval 'db.fsyncUnlock()'

# Restore = mount the snapshot as the new dbPath and start mongod against it.

Atlas / Ops Manager continuous backup

Atlas Backup and Ops Manager (the on-prem product) tail the oplog continuously and keep base snapshots, which together give point-in-time recovery to any second within the retention window, plus scheduled snapshot policies and automated restores. This is managed infrastructure — there is no self-hosted equivalent to run — so this page links it rather than documenting it in depth: Atlas Cloud Backup and Ops Manager Backup.

Sharded clusters

A sharded cluster cannot be backed up shard-by-shard with independent, uncoordinated snapshots: chunk migrations in flight would leave the copies mutually inconsistent. Either stop the balancer first (sh.stopBalancer()) and snapshot every shard plus a config-server member while it is stopped, or use a tool that coordinates the cluster-wide snapshot for you (Atlas, Ops Manager, or mongodump against each component with the balancer off).

mongosh --eval 'sh.stopBalancer()'
# ... snapshot every shard + one config server member ...
mongosh --eval 'sh.startBalancer()'

See Back Up a Sharded Cluster with Filesystem Snapshots and Sharding for what the balancer does and why stopping it matters.

The overview of all methods, side by side, is at MongoDB Backup Methods.

Data movement: mongoexport / mongoimport

mongoexport writes a collection as JSON or CSV; mongoimport reads those formats back. They are for data interchange — feeding a spreadsheet, loading a CSV from another system — not for backups. JSON and CSV cannot represent every BSON type faithfully: an ObjectId, a Decimal128, a Date, a Long, or a binary field either becomes MongoDB Extended JSON ({"$oid": "…​"}) or, in plain CSV, loses its type entirely. Use mongodump/mongorestore whenever type fidelity matters.

# Export selected fields as CSV.
mongoexport --uri "mongodb://localhost:27017/shop" --collection orders \
            --type csv --fields _id,customerId,total,orderDate \
            --query '{ "status": "OPEN" }' --out orders.csv

# Import a JSON-lines file, upserting on _id.
mongoimport --uri "mongodb://localhost:27017/shop" --collection orders \
            --file orders.json --mode upsert --upsertFields _id

bsondump converts a raw .bson file (for example one produced by mongodump) to human-readable JSON for inspection, without a running server.

bsondump --pretty /backups/2026-08-30/shop/orders.bson | head

See mongoexport, mongoimport, bsondump, and Documents & BSON for why the JSON/CSV round trip is lossy and what Extended JSON preserves.

GridFS: files larger than 16 MB

A single BSON document is capped at 16 MB, so a large file cannot be stored as one field. GridFS is a convention — implemented by every driver — that splits a file into 255 KB chunks stored in a <bucket>.chunks collection, with one metadata document per file in <bucket>.files (filename, length, chunkSize, upload date, optional metadata). Reads stream chunk by chunk, and range reads fetch only the chunks they need.

// mongosh has no GridFS helper; drivers do. Node.js driver:
const bucket = new mongodb.GridFSBucket(db, { bucketName: "assets" });

fs.createReadStream("video.mp4")
  .pipe(bucket.openUploadStream("video.mp4", { metadata: { owner: 42 } }));

bucket.openDownloadStreamByName("video.mp4")
      .pipe(fs.createWriteStream("out.mp4"));

mongofiles is the command-line client for the same buckets:

mongofiles --uri "mongodb://localhost:27017/media" put video.mp4
mongofiles --uri "mongodb://localhost:27017/media" list
mongofiles --uri "mongodb://localhost:27017/media" get video.mp4

When not to use GridFS: if you mainly need blob storage with CDN delivery, a dedicated object store (S3, GCS, Azure Blob) is cheaper, serves HTTP directly, and does not put file bytes through the database’s cache and backups. GridFS earns its place when you want files transactionally and operationally alongside your documents — same replication, same backup, same access control — or need atomic-ish range access to portions of a file.

See GridFS and mongofiles.