busboy vs formidable vs multer vs @fastify/multipart
Node.js File Upload Libraries Comparison
1 Year
busboyformidablemulter@fastify/multipartSimilar Packages:
What's Node.js File Upload Libraries?

File upload libraries in Node.js facilitate the handling of multipart/form-data, which is commonly used for uploading files. These libraries provide various functionalities such as parsing incoming request data, managing file streams, and handling file storage. They are essential for building applications that require file uploads, ensuring that developers can efficiently manage file data while adhering to best practices for security and performance.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
busboy15,677,2202,903124 kB36--
formidable10,849,8177,102203 kB504 months agoMIT
multer6,437,66711,70927.6 kB269-MIT
@fastify/multipart252,423501158 kB13a month agoMIT
Feature Comparison: busboy vs formidable vs multer vs @fastify/multipart

Performance

  • busboy:

    Busboy is lightweight and designed for streaming, which allows it to handle file uploads with minimal memory usage. Its performance is excellent for parsing large files as it processes data in chunks rather than loading everything into memory at once.

  • formidable:

    Formidable provides a good balance between performance and ease of use. While it may not be as fast as busboy or @fastify/multipart, it offers a comprehensive feature set that can be advantageous for more complex file handling scenarios.

  • multer:

    Multer is built on top of busboy and provides a middleware layer for Express.js applications. While it may introduce some overhead compared to busboy directly, its ease of integration with Express makes it a popular choice for many developers.

  • @fastify/multipart:

    @fastify/multipart is optimized for performance, leveraging Fastify's asynchronous architecture to handle file uploads efficiently. It minimizes overhead and maximizes throughput, making it suitable for applications with high file upload demands.

Ease of Use

  • busboy:

    Busboy requires more manual setup and handling compared to higher-level libraries. While it offers flexibility, developers may need to write more boilerplate code to manage file uploads effectively.

  • formidable:

    Formidable is user-friendly and provides a high-level API that abstracts much of the complexity involved in file uploads. Its built-in features for file renaming and storage make it easy to use for developers of all skill levels.

  • multer:

    Multer is very easy to set up and use within Express applications. Its middleware approach allows developers to quickly configure file upload handling with minimal code, making it a go-to choice for many Express.js developers.

  • @fastify/multipart:

    @fastify/multipart is designed to be straightforward for Fastify users, providing a simple API that integrates well with Fastify's request lifecycle. Its documentation is clear, making it easy to implement file uploads in Fastify applications.

File Handling Features

  • busboy:

    Busboy provides low-level access to file streams, allowing developers to implement custom file handling logic. However, it does not provide built-in features for file validation or storage, requiring developers to implement these functionalities themselves.

  • formidable:

    Formidable offers a rich set of features, including file renaming, automatic file storage, and customizable upload paths. It also supports handling of both files and fields in a single request, making it versatile for complex forms.

  • multer:

    Multer provides built-in support for file size limits and file type filtering, allowing developers to easily enforce upload constraints. It also supports multiple file uploads and can be configured to store files in memory or on disk.

  • @fastify/multipart:

    @fastify/multipart supports various file handling features, including file size limits, file type validation, and streaming uploads. It allows developers to customize the handling of uploaded files to fit their needs.

Integration

  • busboy:

    Busboy is a standalone library and can be integrated into any Node.js application. However, it requires more manual setup to work with frameworks like Express or Koa, as it does not provide built-in middleware.

  • formidable:

    Formidable can be used in any Node.js application, but it is particularly well-suited for Express due to its straightforward API. It requires minimal configuration to get started and works well with existing Express middleware.

  • multer:

    Multer is specifically designed for use with Express.js, making it easy to integrate as middleware. It fits naturally into the Express request handling flow, allowing for quick setup and configuration.

  • @fastify/multipart:

    @fastify/multipart is specifically designed for Fastify, ensuring seamless integration with its ecosystem. It takes advantage of Fastify's lifecycle hooks and asynchronous capabilities for optimal performance.

Community and Support

  • busboy:

    Busboy has a smaller community compared to some other libraries, but it is well-maintained and has been widely adopted in the Node.js ecosystem. Documentation is available, but may not be as extensive as other libraries.

  • formidable:

    Formidable has been around for a long time and has a strong user base. It offers good documentation and community support, making it a reliable choice for developers seeking assistance.

  • multer:

    Multer enjoys a large community due to its popularity within the Express ecosystem. It has extensive documentation and numerous tutorials available, making it easy for developers to find help and resources.

  • @fastify/multipart:

    @fastify/multipart benefits from the growing Fastify community, which provides active support and a wealth of resources for developers. Its documentation is comprehensive and regularly updated.

How to Choose: busboy vs formidable vs multer vs @fastify/multipart
  • busboy:

    Choose busboy if you are looking for a lightweight and low-level streaming parser for multipart form data. It is suitable for applications where you want fine-grained control over file uploads and processing, and you don't need additional features that come with higher-level libraries.

  • formidable:

    Choose formidable if you need a robust solution that supports file uploads and form parsing with a focus on ease of use. It provides a comprehensive set of features, including file renaming and storage options, making it a good choice for applications that require more than just basic file handling.

  • multer:

    Choose multer if you are using Express.js and need a middleware for handling multipart/form-data. It is easy to set up and provides a simple API for configuring file storage options, making it ideal for applications that require quick and straightforward file upload functionality.

  • @fastify/multipart:

    Choose @fastify/multipart if you are using the Fastify framework and need a high-performance solution that integrates seamlessly with Fastify's ecosystem. It is designed for speed and efficiency, making it ideal for applications that require handling large file uploads.

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.