npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

express-mongo-gridfs

v1.2.1

Published

A premium, enterprise-ready toolkit for seamless integration of Express.js and MongoDB GridFS, designed to simplify file storage and retrieval with robust features and exceptional performance.

Readme

🚀 express-mongo-gridfs

npm version License NPM Downloads

A premium, enterprise-ready toolkit for professional file management in MongoDB using GridFS.
Build robust, scalable, and fully-documented file APIs in minutes.


📑 Table of Contents


📋 Prerequisites

  • Node.js: v18.0.0+
  • MongoDB: v5.0+ (GridFS support)
  • Replica Set: Mandatory for transactions (replaceFilesWithTransaction).

[!IMPORTANT]
🔗 Refer to the Official Mongoose Guide to Replica Sets for setup.


💾 Installation

npm install express-mongo-gridfs

🧩 Core Initialization

Initialize the library once your Mongoose connection is established. This sets up the internal GridFSBucket.

import { initGridFS } from 'express-mongo-gridfs';
import mongoose from 'mongoose';

async function connectDatabase(connectionString) {
  try {
    await mongoose.connect(connectionString, { family: 4 });
    console.log("✅ Connected to DB successfully");
    
    // 🛡️ CRITICAL: Initialize GridFS with the connection
    initGridFS(mongoose.connection);
  } catch (err) {
    console.error("❌ Database connection error:", err);
    throw err;
  }
}

🏗 Model Management

The createFilesModel function generates a Mongoose model specifically tuned for GridFS metadata. It handles collection naming, schema merging, and schema options (including indexing, transforms, and virtuals).

⚙️ Model Configuration Deep Dive

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | collection | string | 'upload' | Base name for the collections. | | modelSchema | object | {} | Mongoose schema definition to merge into the base file schema. | | schemaOptions | object | {} | Standard Mongoose Schema options object. Can configure toJSON, toObject, timestamps, strict, and other schema-level behaviors. |

🔍 Default Logic & Naming

  • Collection Name: The underlying MongoDB collection will be ${collection}.files.
  • Model Name: The Mongoose model is registered as ${CapitalizedCollection}File.
    Example: A collection named media becomes MediaFile.
  • Base Schema: Every model includes filename, contentType, length, chunkSize, uploadDate, and metadata by default.

📝 Schema Extension Example

import { createFilesModel } from 'express-mongo-gridfs';

const UserDocs = createFilesModel({
  collection: 'user_docs',
  modelSchema: {
    owner: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
    category: { type: String, enum: ['invoice', 'id_card', 'other'] },
    isVerified: { type: Boolean, default: false }
  },
  schemaOptions: {
    toJSON: { virtuals: true, transformer: yourTransFormerFn },
    toObject: { virtuals: true, transformer: yourTransFormerFn }
  }
});

// additional settings
UserDocs.schema.index({ category: 1 }); 
UserDocs.syncIndexes();

🌐 Express Router Factory

The createFileRouter factory creates a standard Express router with optimized handlers for file operations.

🛠 Router Configuration Options

// Create the user files router with exact original routes and Swagger
const userFilesRouter = createFileRouter({
    model: UserFile,
    multerConfig: {
        storage: multer.memoryStorage(),
        limits: {
            fileSize: 20 * 1024 * 1024, // 20MB per file
            files: 5 // Maximum 5 files per upload
        },
        fileFilter: (req, file, cb) => {
            // Define allowed MIME types for all supported formats
            const allowedMimes = [
                //images
                'image/jpeg',
                'image/jpg',
                'image/png',
                //pdf
                'application/pdf',
                //word
                'application/msword'
            ];

            if (allowedMimes.includes(file.mimetype)) {
                cb(null, true);
            } else {
                cb(new Error('Invalid file type. Supported formats: images, PDF.'), false);
            }
        }
    },
    routeMiddlewares: {
        // Auth middleware on ALL routes
        upload: [your_auth_middleware, your_rate_limiter],
        list: [your_auth_middleware],
        get: [your_auth_middleware],
        download: [your_auth_middleware],
        update: [your_auth_middleware],
        bulkUpload: [your_auth_middleware],
        delete: [your_AuthMiddleware],
        deleteBulk: [your_AuthMiddleware],
    },
    swaggerConfig: {
        tags: ['User Files']
    }
});

➕ Extending the Router

Since it returns a standard express.Router, you can mount additional logic easily:

const fileRouter = createFileRouter({ model: UserDocs });

// Extend with a custom analytics route
fileRouter.get('/stats/summary', async (req, res) => {
  const stats = await UserDocs.aggregate([...]);
  res.json(stats);
});

app.use('/api/files', fileRouter);

🔐 Automatic User Attribution

If your middleware (e.g., Passport, JWT) attaches a user object to the req with an id or _id, the library will automatically attribute uploadedBy to that ID if it isn't explicitly provided in the request body.

This is supported in:

  • POST /upload
  • POST /upload-files (Bulk)

📄 Swagger Setup Guide

Add the library routes to your existing Swagger documentation:

import swaggerJSDoc from "swagger-jsdoc";

const swaggerOptions = {
  definition: {
    openapi: "3.0.0",
    info: {
      title: "My System API",
      version: "1.0.0",
      description: "API for managing files and users"
    },
  },
  apis: [
    "./src/routes/*.js",              // Your existing routes
    "./src/modules/files/*.js",       // Where Your created Routers are
  ],
};

const swaggerSpecs = swaggerJSDoc(swaggerOptions);
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerSpecs));

🛠 Exhaustive Utilities API

📂 File Operations

uploadFile(model, file, body)

Uploads a file and persists metadata.

const result = await uploadFile(UserDocs, req.file, { 
  owner: req.user._id, 
  category: 'invoice' 
});

replaceFile(model, id, file, body)

Updates an existing file by creating new chunks and cleaning up the old ones.

const result = await replaceFile(UserDocs, '64af...', req.file, { category: 'updated' });

replaceFiles(model, files, body)

Bulk operation. Updates if file ID/name is provided; otherwise, creates new entries.

const response = await replaceFiles(UserDocs, req.files, req.body);

deleteFiles(model, ids)

Safely removes metadata and GridFS chunks for one or more IDs. Supports arrays or comma-separated strings.

deleteFile(model, id)

Shorthand for deleteFiles(model, id).

getFileAndBuffer(model, id)

Retrieves metadata and full binary content as a Buffer. Perfect for custom processing.

🛡 Transaction Support

replaceFilesWithTransaction(model, files, body)

Ensures atomicity for bulk operations. If one file fails, the entire operation is rolled back.

try {
  const report = await replaceFilesWithTransaction(UserDocs, req.files, req.body);
  console.log('✅ Processed:', report.summary);
} catch (err) {
  console.error('❌ Transaction rolled back:', err.message);
}

⚠️ Error Handling & Storage Logic

  • 🛡️ Orphan Prevention: If a metadata save fails after writing chunks, the library triggers a best-effort cleanup of the orphaned chunks.
  • 🛡️ Safety First: During file updates, the new data is committed before the old data is deleted, ensuring no "missing file" window.
  • 🛡️ Granular Feedback: Batch operations return a 207 Multi-Status on partial failure, providing a detailed summary (including successful count) and errors array.
  • 🛡️ Smart Response: Single upload responses merge any custom schema-defined root fields into the metadata object for easier client-side consumption.

📄 License

ISC


🤝 Contributing

Contributions are welcome! Please open an issue or submit a pull request.