Ch. 12 · MongoDB

MongoDB GridFS for Large Files

Store files larger than the 16 MB document limit with GridFS, streaming uploads and downloads and cleaning up orphaned chunks.

~2 min readadvancedupdated Oct 5, 2026

A BSON document is limited to 16 MB, so large files cannot live in a single document field. GridFS stores a file as multiple chunk documents plus a metadata document, letting you stream uploads and downloads and query metadata without loading the whole file.

Before you start

You should be comfortable with the Node.js driver and streams. This article uses the driver’s GridFSBucket.

Step-by-step walkthrough

Step 1: Choose a bucket

A GridFSBucket (or the default fs) groups the files and chunks collections for a set of files. Naming the bucket per feature keeps uploads organized and makes cleanup scoped. The bucket handles chunking and metadata.

Step 2: Stream uploads and downloads

bucket.openUploadStream(name) returns a writable stream, so you pipe a file stream into it without buffering the whole file in memory. Downloads use openDownloadStream, which streams chunks back. Streaming is what makes large files practical.

Step 3: Store metadata and clean up

Attach metadata such as content type and owner at upload time so files are findable, and delete through the bucket to remove both the metadata and its chunks together. An abandoned upload can leave orphaned chunks, so handle errors and remove partial uploads.

Worked scenario

The upload streams a file into a GridFS bucket.

import fs from 'node:fs';
import { GridFSBucket } from 'mongodb';

const bucket = new GridFSBucket(db, { bucketName: 'uploads' });
await new Promise((resolve, reject) => {
  fs.createReadStream('photo.jpg')
    .pipe(bucket.openUploadStream('photo.jpg', { metadata: { type: 'image/jpeg' } }))
    .on('finish', resolve)
    .on('error', reject);
});
JavaScript

Walk through the example

The read stream feeds the upload stream, so the file is chunked and written without loading it entirely. The metadata travels with the file document, so a query can find it by owner or type. On error, the promise rejects, which lets the caller delete the partial upload.

Common mistake

Storing large binaries as base64 in a normal document, which hits the 16 MB limit and bloats the working set. Another is deleting the file document without its chunks, leaving orphans that waste space.

Verify the behavior

Upload a file larger than 16 MB and confirm it succeeds where a normal insert fails. Download it and compare a checksum with the original. Delete through the bucket and confirm both the file document and its chunks are removed.

Interview exercise

Why does GridFS help beyond the 16 MB limit?

Answer and reasoning

It splits a file into small chunk documents, so each stays under the limit while the whole file can be any size. It also enables streaming, so uploads and downloads use bounded memory, and it stores metadata separately, so you can query files without reading their contents. The limit is the trigger; streaming and metadata are the real benefits.

Continue learning

Compare storage choices in Embedding and referencing and document atomicity in Document atomicity. Read the MongoDB GridFS documentation and try the MongoDB interview questions.

More in MongoDB

read ✓MongoDB · mid

MongoDB Bulk Writes

Batch inserts and updates with bulkWrite, choose ordered or unordered, and handle partial failures correctly.

~2 min readread →
read ✓MongoDB · mid

MongoDB Capped Collections

Use capped collections for fixed-size, insertion-ordered logs, and know why documents cannot grow.

~2 min readread →
read ✓MongoDB · hard

MongoDB Change Streams and Resume Tokens

React to inserts and updates with change streams, persist resume tokens, and handle invalidate and failover correctly.

~2 min readread →
esc