busboy vs formidable vs multer vs express-fileupload vs connect-multiparty vs connect-busboy
File Upload Handling in Node.js Comparison
1 Year
busboyformidablemulterexpress-fileuploadconnect-multipartyconnect-busboySimilar Packages:
What's File Upload Handling in Node.js?

File upload handling libraries in Node.js provide tools to manage file uploads from clients to servers. These libraries parse incoming multipart/form-data requests, extract files and fields, and provide APIs to access the uploaded data. They handle various aspects of file uploads, including streaming, validation, storage, and error handling, making it easier for developers to implement file upload functionality in their applications. Each library has its own approach, features, and trade-offs, catering to different use cases and performance requirements.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
busboy15,532,9142,903124 kB35--
formidable10,812,4917,102203 kB504 months agoMIT
multer6,374,39311,70927.6 kB269-MIT
express-fileupload375,0121,541116 kB237 months agoMIT
connect-multiparty78,786349-06 years agoMIT
connect-busboy43,7511554.57 kB0--
Feature Comparison: busboy vs formidable vs multer vs express-fileupload vs connect-multiparty vs connect-busboy

Streaming vs. Buffering

  • busboy:

    busboy streams file uploads directly, which means it processes files in chunks as they are received. This approach minimizes memory usage, making it ideal for handling large files without loading them entirely into memory.

  • formidable:

    formidable supports both streaming and buffering of file uploads. It streams files to disk as they are uploaded, which helps manage memory usage while still providing access to file data in a structured way.

  • multer:

    multer buffers file uploads in memory or saves them directly to disk, depending on the storage configuration. It provides flexibility in handling files while allowing for memory-efficient processing with the right setup.

  • express-fileupload:

    express-fileupload buffers file uploads in memory by default, which can lead to increased memory usage for large files. However, it allows for configuration of file size limits and supports streaming uploads with additional setup.

  • connect-multiparty:

    connect-multiparty buffers file uploads in memory or on disk, depending on the configuration. This can lead to higher memory usage, especially with large files, but it simplifies the handling of files and form fields.

  • connect-busboy:

    connect-busboy inherits the streaming behavior of busboy, allowing for efficient file processing with low memory consumption. It streams files while providing middleware integration for Express and Connect applications.

Integration with Express

  • busboy:

    busboy is a low-level library that does not provide direct integration with Express. However, it can be easily used within Express routes to handle file uploads with custom middleware.

  • formidable:

    formidable can be used as middleware in Express applications, but it requires some setup to integrate it properly. It provides a robust solution for handling file uploads with more features than basic middleware.

  • multer:

    multer is specifically designed for use with Express. It provides easy-to-use middleware for handling multipart/form-data, making it a popular choice for file uploads in Express applications.

  • express-fileupload:

    express-fileupload is an Express middleware that provides a simple way to handle file uploads. It integrates easily into Express applications with minimal configuration, making it user-friendly for developers.

  • connect-multiparty:

    connect-multiparty is a middleware for Connect and Express that simplifies the handling of multipart/form-data. It integrates easily with Express routes, allowing for straightforward file and form field processing.

  • connect-busboy:

    connect-busboy is designed for seamless integration with Connect and Express frameworks. It provides middleware that wraps busboy, making it easy to handle file uploads in Express applications.

File Size Limits

  • busboy:

    busboy allows you to set file size limits at the stream level, helping to prevent large files from being processed. However, you need to implement the logic for handling size limits manually.

  • formidable:

    formidable supports file size limits and allows you to configure them easily. It provides error handling for files that exceed the specified limits, helping to manage resource usage during uploads.

  • multer:

    multer allows you to set file size limits at the field level, providing fine-grained control over file uploads. It also includes built-in error handling for files that exceed the specified limits.

  • express-fileupload:

    express-fileupload allows you to set file size limits easily through configuration. It provides built-in error handling for files that exceed the specified limits, making it straightforward to manage file size restrictions.

  • connect-multiparty:

    connect-multiparty allows you to set file size limits for uploads, and it provides error handling for files that exceed the specified limits. This feature helps prevent excessive memory usage and potential denial-of-service attacks.

  • connect-busboy:

    connect-busboy inherits file size limit handling from busboy, allowing you to set limits on file sizes. It provides a way to handle size limit errors within the middleware.

Code Example

  • busboy:

    busboy Example

    const Busboy = require('busboy');
    const fs = require('fs');
    const express = require('express');
    const app = express();
    
    app.post('/upload', (req, res) => {
      const busboy = new Busboy({ headers: req.headers });
      busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        console.log(`Uploading: ${filename}`);
        file.pipe(fs.createWriteStream(`./uploads/${filename}`));
      });
      busboy.on('finish', () => {
        res.send('Upload complete');
      });
      req.pipe(busboy);
    });
    
    app.listen(3000, () => {
      console.log('Server listening on port 3000');
    });
    
  • formidable:

    formidable Example

    const express = require('express');
    const formidable = require('formidable');
    const fs = require('fs');
    const app = express();
    
    app.post('/upload', (req, res) => {
      const form = new formidable.IncomingForm();
      form.uploadDir = './uploads';
      form.on('file', (field, file) => {
        const newPath = `${form.uploadDir}/${file.name}`;
        fs.renameSync(file.path, newPath);
        console.log(`Uploaded: ${file.name}`);
      });
      form.on('end', () => res.send('Upload complete'));
      form.parse(req);
    });
    
    app.listen(3000, () => {
      console.log('Server listening on port 3000');
    });
    
  • multer:

    multer Example

    const express = require('express');
    const multer = require('multer');
    const fs = require('fs');
    const app = express();
    const upload = multer({ dest: './uploads/' });
    
    app.post('/upload', upload.array('files', 12), (req, res) => {
      req.files.forEach(file => {
        console.log(`Uploaded: ${file.originalname}`);
      });
      res.send('Upload complete');
    });
    
    app.listen(3000, () => {
      console.log('Server listening on port 3000');
    });
    
  • express-fileupload:

    express-fileupload Example

    const express = require('express');
    const fileUpload = require('express-fileupload');
    const app = express();
    
    app.use(fileUpload());
    
    app.post('/upload', (req, res) => {
      const { files } = req;
      Object.keys(files).forEach(field => {
        const file = files[field];
        file.mv(`./uploads/${file.name}`, err => {
          if (err) return res.status(500).send(err);
          console.log(`Uploaded: ${file.name}`);
        });
      });
      res.send('Upload complete');
    });
    
    app.listen(3000, () => {
      console.log('Server listening on port 3000');
    });
    
  • connect-multiparty:

    connect-multiparty Example

    const express = require('express');
    const multiparty = require('connect-multiparty');
    const fs = require('fs');
    const app = express();
    const multipartyMiddleware = multiparty();
    
    app.post('/upload', multipartyMiddleware, (req, res) => {
      const { files } = req;
      Object.keys(files).forEach(field => {
        const file = files[field];
        const filePath = `./uploads/${file.originalFilename}`;
        fs.renameSync(file.path, filePath);
        console.log(`Uploaded: ${file.originalFilename}`);
      });
      res.send('Upload complete');
    });
    
    app.listen(3000, () => {
      console.log('Server listening on port 3000');
    });
    
  • connect-busboy:

    connect-busboy Example

    const express = require('express');
    const connectBusboy = require('connect-busboy');
    const fs = require('fs');
    const app = express();
    
    app.use(connectBusboy());
    
    app.post('/upload', (req, res) => {
      req.busboy.on('file', (fieldname, file, filename) => {
        console.log(`Uploading: ${filename}`);
        file.pipe(fs.createWriteStream(`./uploads/${filename}`));
      });
      req.busboy.on('finish', () => {
        res.send('Upload complete');
      });
    });
    
    app.listen(3000, () => {
      console.log('Server listening on port 3000');
    });
    
How to Choose: busboy vs formidable vs multer vs express-fileupload vs connect-multiparty vs connect-busboy
  • busboy:

    Choose busboy if you need a lightweight, streaming parser for multipart/form-data that provides fine-grained control over file uploads. It is ideal for applications that require low-level access to the upload process and want to minimize memory usage.

  • formidable:

    Select formidable if you need a feature-rich library that supports streaming file uploads, file size limits, and automatic handling of form fields. It is suitable for applications that require more advanced features like file renaming, progress tracking, and custom file handling.

  • multer:

    Choose multer if you are looking for a middleware specifically designed for handling multipart/form-data in Express applications. It is easy to use, supports file uploads, and allows for fine-grained control over file storage, naming, and validation.

  • express-fileupload:

    Choose express-fileupload if you want a simple and easy-to-use middleware for handling file uploads in Express applications. It supports single and multiple file uploads, file size limits, and provides a straightforward API with minimal configuration.

  • connect-multiparty:

    Use connect-multiparty if you need a simple and straightforward solution for handling multipart/form-data in Connect or Express applications. It supports file uploads and form fields but is less actively maintained than other options.

  • connect-busboy:

    Select connect-busboy if you are using the Connect or Express framework and want to integrate busboy easily. It provides middleware for handling file uploads while maintaining the simplicity and efficiency of busboy.

README for busboy

Description

A node.js module for parsing incoming HTML form data.

Changes (breaking or otherwise) in v1.0.0 can be found here.

Requirements

Install

npm install busboy

Examples

  • Parsing (multipart) with default options:
const http = require('http');

const busboy = require('busboy');

http.createServer((req, res) => {
  if (req.method === 'POST') {
    console.log('POST request');
    const bb = busboy({ headers: req.headers });
    bb.on('file', (name, file, info) => {
      const { filename, encoding, mimeType } = info;
      console.log(
        `File [${name}]: filename: %j, encoding: %j, mimeType: %j`,
        filename,
        encoding,
        mimeType
      );
      file.on('data', (data) => {
        console.log(`File [${name}] got ${data.length} bytes`);
      }).on('close', () => {
        console.log(`File [${name}] done`);
      });
    });
    bb.on('field', (name, val, info) => {
      console.log(`Field [${name}]: value: %j`, val);
    });
    bb.on('close', () => {
      console.log('Done parsing form!');
      res.writeHead(303, { Connection: 'close', Location: '/' });
      res.end();
    });
    req.pipe(bb);
  } else if (req.method === 'GET') {
    res.writeHead(200, { Connection: 'close' });
    res.end(`
      <html>
        <head></head>
        <body>
          <form method="POST" enctype="multipart/form-data">
            <input type="file" name="filefield"><br />
            <input type="text" name="textfield"><br />
            <input type="submit">
          </form>
        </body>
      </html>
    `);
  }
}).listen(8000, () => {
  console.log('Listening for requests');
});

// Example output:
//
// Listening for requests
//   < ... form submitted ... >
// POST request
// File [filefield]: filename: "logo.jpg", encoding: "binary", mime: "image/jpeg"
// File [filefield] got 11912 bytes
// Field [textfield]: value: "testing! :-)"
// File [filefield] done
// Done parsing form!
  • Save all incoming files to disk:
const { randomFillSync } = require('crypto');
const fs = require('fs');
const http = require('http');
const os = require('os');
const path = require('path');

const busboy = require('busboy');

const random = (() => {
  const buf = Buffer.alloc(16);
  return () => randomFillSync(buf).toString('hex');
})();

http.createServer((req, res) => {
  if (req.method === 'POST') {
    const bb = busboy({ headers: req.headers });
    bb.on('file', (name, file, info) => {
      const saveTo = path.join(os.tmpdir(), `busboy-upload-${random()}`);
      file.pipe(fs.createWriteStream(saveTo));
    });
    bb.on('close', () => {
      res.writeHead(200, { 'Connection': 'close' });
      res.end(`That's all folks!`);
    });
    req.pipe(bb);
    return;
  }
  res.writeHead(404);
  res.end();
}).listen(8000, () => {
  console.log('Listening for requests');
});

API

Exports

busboy exports a single function:

( function )(< object >config) - Creates and returns a new Writable form parser stream.

  • Valid config properties:

    • headers - object - These are the HTTP headers of the incoming request, which are used by individual parsers.

    • highWaterMark - integer - highWaterMark to use for the parser stream. Default: node's stream.Writable default.

    • fileHwm - integer - highWaterMark to use for individual file streams. Default: node's stream.Readable default.

    • defCharset - string - Default character set to use when one isn't defined. Default: 'utf8'.

    • defParamCharset - string - For multipart forms, the default character set to use for values of part header parameters (e.g. filename) that are not extended parameters (that contain an explicit charset). Default: 'latin1'.

    • preservePath - boolean - If paths in filenames from file parts in a 'multipart/form-data' request shall be preserved. Default: false.

    • limits - object - Various limits on incoming data. Valid properties are:

      • fieldNameSize - integer - Max field name size (in bytes). Default: 100.

      • fieldSize - integer - Max field value size (in bytes). Default: 1048576 (1MB).

      • fields - integer - Max number of non-file fields. Default: Infinity.

      • fileSize - integer - For multipart forms, the max file size (in bytes). Default: Infinity.

      • files - integer - For multipart forms, the max number of file fields. Default: Infinity.

      • parts - integer - For multipart forms, the max number of parts (fields + files). Default: Infinity.

      • headerPairs - integer - For multipart forms, the max number of header key-value pairs to parse. Default: 2000 (same as node's http module).

This function can throw exceptions if there is something wrong with the values in config. For example, if the Content-Type in headers is missing entirely, is not a supported type, or is missing the boundary for 'multipart/form-data' requests.

(Special) Parser stream events

  • file(< string >name, < Readable >stream, < object >info) - Emitted for each new file found. name contains the form field name. stream is a Readable stream containing the file's data. No transformations/conversions (e.g. base64 to raw binary) are done on the file's data. info contains the following properties:

    • filename - string - If supplied, this contains the file's filename. WARNING: You should almost never use this value as-is (especially if you are using preservePath: true in your config) as it could contain malicious input. You are better off generating your own (safe) filenames, or at the very least using a hash of the filename.

    • encoding - string - The file's 'Content-Transfer-Encoding' value.

    • mimeType - string - The file's 'Content-Type' value.

    Note: If you listen for this event, you should always consume the stream whether you care about its contents or not (you can simply do stream.resume(); if you want to discard/skip the contents), otherwise the 'finish'/'close' event will never fire on the busboy parser stream. However, if you aren't accepting files, you can either simply not listen for the 'file' event at all or set limits.files to 0, and any/all files will be automatically skipped (these skipped files will still count towards any configured limits.files and limits.parts limits though).

    Note: If a configured limits.fileSize limit was reached for a file, stream will both have a boolean property truncated set to true (best checked at the end of the stream) and emit a 'limit' event to notify you when this happens.

  • field(< string >name, < string >value, < object >info) - Emitted for each new non-file field found. name contains the form field name. value contains the string value of the field. info contains the following properties:

    • nameTruncated - boolean - Whether name was truncated or not (due to a configured limits.fieldNameSize limit)

    • valueTruncated - boolean - Whether value was truncated or not (due to a configured limits.fieldSize limit)

    • encoding - string - The field's 'Content-Transfer-Encoding' value.

    • mimeType - string - The field's 'Content-Type' value.

  • partsLimit() - Emitted when the configured limits.parts limit has been reached. No more 'file' or 'field' events will be emitted.

  • filesLimit() - Emitted when the configured limits.files limit has been reached. No more 'file' events will be emitted.

  • fieldsLimit() - Emitted when the configured limits.fields limit has been reached. No more 'field' events will be emitted.