busboy vs formidable vs multer vs express-fileupload
Node.js File Upload Libraries Comparison
1 Year
busboyformidablemulterexpress-fileuploadSimilar Packages:
What's Node.js File Upload Libraries?

File upload libraries in Node.js facilitate the handling of file uploads from clients to servers. These libraries simplify the process of parsing incoming multipart/form-data requests, managing file storage, and providing various options for file validation and processing. They are essential for applications that require user-uploaded files, such as image uploads, document submissions, and more. Each library offers unique features and trade-offs, making it important to choose the right one based on project requirements.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
busboy16,015,7712,901124 kB36--
formidable10,814,8217,105203 kB504 months agoMIT
multer6,534,33511,71327.6 kB269-MIT
express-fileupload374,0321,542116 kB238 months agoMIT
Feature Comparison: busboy vs formidable vs multer vs express-fileupload

Performance

  • busboy:

    Busboy is designed for high performance and low memory usage. It streams the file data directly to the destination without buffering the entire file in memory, making it suitable for handling large files efficiently.

  • formidable:

    Formidable provides a good balance between ease of use and performance. It streams file uploads and supports large files, but it may not be as lightweight as Busboy. It is suitable for applications that require a more feature-rich solution.

  • multer:

    Multer is built on top of the Express framework and is optimized for performance. It allows for easy file uploads and provides options for file size limits and storage configurations, making it a good choice for Express applications.

  • express-fileupload:

    Express-fileupload is relatively simple and easy to use, but it may not be as performant as Busboy for large files since it buffers the entire file in memory before processing, which can lead to higher memory consumption.

Ease of Use

  • busboy:

    Busboy requires more manual setup and configuration, making it less beginner-friendly. Developers need to handle streams and file management explicitly, which may increase complexity for simple applications.

  • formidable:

    Formidable offers a straightforward API that is easy to understand, making it accessible for developers. It provides built-in support for file uploads and form parsing, simplifying the development process.

  • multer:

    Multer is also easy to use, especially for those already familiar with Express. It provides a simple API for handling file uploads and integrates well with Express middleware, making it a popular choice.

  • express-fileupload:

    Express-fileupload is very easy to set up and use, making it ideal for quick implementations. It requires minimal configuration and integrates seamlessly with Express, allowing for rapid development.

File Validation and Processing

  • busboy:

    Busboy does not provide built-in file validation features, so developers need to implement their own validation logic. This allows for greater flexibility but requires additional coding effort.

  • formidable:

    Formidable supports file validation and provides options for handling file types and sizes. It allows developers to set limits on file uploads, making it easier to manage user submissions.

  • multer:

    Multer offers extensive file validation options, including file type and size limits. It allows developers to define custom storage engines and validation logic, providing a robust solution for file uploads.

  • express-fileupload:

    Express-fileupload includes basic file validation options, such as checking file types and sizes, making it easier for developers to enforce upload constraints without additional code.

Extensibility

  • busboy:

    Busboy is highly extensible due to its low-level nature, allowing developers to implement custom logic for file handling and processing. However, this requires more effort and understanding of streams.

  • formidable:

    Formidable provides a good level of extensibility, allowing developers to customize file handling and processing. It supports various file storage options and can be adapted to different use cases.

  • multer:

    Multer is highly extensible, allowing developers to create custom storage engines and middleware. This makes it suitable for a wide range of applications, from simple to complex file upload scenarios.

  • express-fileupload:

    Express-fileupload is less extensible compared to others, as it is designed for simplicity. While it covers basic use cases well, it may not offer the flexibility needed for more complex scenarios.

Community and Support

  • busboy:

    Busboy has a smaller community compared to other libraries, which may result in fewer resources and examples available for troubleshooting and support.

  • formidable:

    Formidable has been around for a long time and has a strong community. It is well-documented, and many developers have shared their experiences and solutions online.

  • multer:

    Multer is one of the most popular file upload libraries for Express, boasting a large community and extensive documentation. This makes it easy to find support and examples for common use cases.

  • express-fileupload:

    Express-fileupload has a growing community and is widely used, providing ample resources, documentation, and community support for developers.

How to Choose: busboy vs formidable vs multer vs express-fileupload
  • busboy:

    Choose Busboy if you need a lightweight and efficient streaming parser for handling file uploads. It is ideal for applications that require low-level control over file processing and want to handle streams directly.

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.