SkillAgentSearch skills...

Formidable

The most used, flexible, fast and streaming parser for multipart form data. Supports uploading to serverless environments, AWS S3, Azure, GCP or the filesystem. Used in production.

Install / Use

/learn @node-formidable/Formidable

README

<p align="center"> <img alt="npm formidable package logo" src="https://raw.githubusercontent.com/node-formidable/formidable/master/logo.png" /> </p>

formidable [![npm version][npmv-img]][npmv-url] [![MIT license][license-img]][license-url] [![Libera Manifesto][libera-manifesto-img]][libera-manifesto-url] [![Twitter][twitter-img]][twitter-url]

A Node.js module for parsing form data, especially file uploads.

[![Code style][codestyle-img]][codestyle-url] [![linux build status][linux-build-img]][build-url] [![macos build status][macos-build-img]][build-url]

<!-- [![codecoverage][codecov-img]][codecov-url] -->

If you have any how-to kind of questions, please read the [Contributing Guide][contributing-url] and [Code of Conduct][code_of_conduct-url] documents.<br /> For bugs reports and feature requests, [please create an issue][open-issue-url] or ping [@wgw_eth / @wgw_lol][twitter-url] at Twitter.

[![Conventional Commits][ccommits-img]][ccommits-url] [![Minimum Required Nodejs][nodejs-img]][npmv-url] [![Buy me a Kofi][kofi-img]][kofi-url] [![Make A Pull Request][prs-welcome-img]][prs-welcome-url]

<!-- [![Tidelift Subscription][tidelift-img]][tidelift-url] --> <!-- [![Renovate App Status][renovateapp-img]][renovateapp-url] -->

This project is semantically versioned and if you want support in migrating between versions you can schedule us for training or support us through donations, so we can prioritize.

[!CAUTION] As of April 2025, old versions like v1 and v2 are still the most used, while they are deprecated for years -- they are also vulnerable to attacks if you are not implementing it properly. Please upgrade! We are here to help, and AI Editors & Agents could help a lot in such codemod-like migrations.

[!TIP] If you are starting a fresh project, you can check out the formidable-mini which is a super minimal version of Formidable (not quite configurable yet, but when it does it could become the basis for formidable@v4), using web standards like FormData API and File API, and you can use it to stream uploads directly to S3 or other such services.

<!-- This project is [semantically versioned](https://semver.org) and available as part of the [Tidelift Subscription][tidelift-url] for professional grade assurances, enhanced support and security. [Learn more.](https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise) _The maintainers of `formidable` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the Open Source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use._ -->

[![][npm-weekly-img]][npmv-url] [![][npm-monthly-img]][npmv-url] [![][npm-yearly-img]][npmv-url] [![][npm-alltime-img]][npmv-url]

Project Status: Maintained

[!NOTE] Check VERSION NOTES for more information on v1, v2, and v3 plans, NPM dist-tags and branches._

This module was initially developed by @felixge for Transloadit, a service focused on uploading and encoding images and videos. It has been battle-tested against hundreds of GBs of file uploads from a large variety of clients and is considered production-ready and is used in production for years.

Currently, we are few maintainers trying to deal with it. :) More contributors are always welcome! :heart: Jump on issue #412 which is closed, but if you are interested we can discuss it and add you after strict rules, like enabling Two-Factor Auth in your npm and GitHub accounts.

Highlights

Install

This package is a dual ESM/commonjs package.

[!NOTE] This project requires Node.js >= 20. Install it using yarn or npm.<br /> We highly recommend to use Yarn when you think to contribute to this project.

This is a low-level package, and if you're using a high-level framework it may already be included. Check the examples below and the examples/ folder.

# v2
npm install formidable@v2

# v3
npm install formidable
npm install formidable@v3

Note: Future not ready releases will be published on *-next dist-tags for the corresponding version.

Examples

For more examples look at the examples/ directory.

with Node.js http module

Parse an incoming file upload, with the Node.js's built-in http module.

import http from 'node:http';
import formidable, {errors as formidableErrors} from 'formidable';

const server = http.createServer(async (req, res) => {
  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {
    // parse a file upload
    const form = formidable({});
    let fields;
    let files;
    try {
        [fields, files] = await form.parse(req);
    } catch (err) {
        // example to check for a very specific error
        if (err.code === formidableErrors.maxFieldsExceeded) {

        }
        console.error(err);
        res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
        res.end(String(err));
        return;
    }
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ fields, files }, null, 2));
    return;
  }

  // show a file upload form
  res.writeHead(200, { 'Content-Type': 'text/html' });
  res.end(`
    <h2>With Node.js <code>"http"</code> module</h2>
    <form action="/api/upload" enctype="multipart/form-data" method="post">
      <div>Text field title: <input type="text" name="title" /></div>
      <div>File: <input type="file" name="multipleFiles" multiple="multiple" /></div>
      <input type="submit" value="Upload" />
    </form>
  `);
});

server.listen(8080, () => {
  console.log('Server listening on http://localhost:8080/ ...');
});

with Express.js

There are multiple variants to do this, but Formidable just need Node.js Request stream, so something like the following example should work just fine, without any third-party Express.js middleware.

Or try the examples/with-express.js

import express from 'express';
import formidable from 'formidable';

const app = express();

app.get('/', (req, res) => {
  res.send(`
    <h2>With <code>"express"</code> npm package</h2>
    <form action="/api/upload" enctype="multipart/form-data" method="post">
      <div>Text field title: <input type="text" name="title" /></div>
      <div>File: <input type="file" name="someExpressFiles" multiple="multiple" /></div>
      <input type="submit" value="Upload" />
    </form>
  `);
});

app.post('/api/upload', (req, res, next) => {
  const form = formidable({});

  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }
    res.json({ fields, files });
  });
});

app.listen(3000, () => {
  console.log('Server listening on http://localhost:3000 ...');
});

with Koa and Formidable

Of course, with Koa v1, v2 or future v3 the things are very similar. You can use formidable manually as shown below or through the koa-better-body package which is using formidable under the hood and support more features and different request bodies, check its documentation for more info.

Note: this example is assuming Koa v2. Be aware that you should pass ctx.req which is Node.js's Request, and NOT the ctx.request which is Koa's Request object - there is a difference.

import Koa from 'Koa';
import formidable from 'formidable';

const app = new Koa();

app.on('error', (err) => {
  console.error('server error', err);
});

app.use(async (ctx, next) => {
  if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') {
    const form = formidable({});

    // not very elegant, but that's for now if you don't want to use `koa-better-body`
    // or other middlewares.
    await new Promise((resolve, reject) => {
      form.parse(ctx.req, (err, fields, files) => {
        if (err) {
          reject(err);
          return;
        }

        ctx.set('Content-Type', 'application/json');
        ctx.status = 200;
        ctx.state = { fields, files };
        ctx.body = JSON.stringify(ctx.state, null, 2);
        resolve();
      });
    });
    await next();
    return;
  }

  // show a file upload form
  ctx.set('Content-Type', 'text/html');
  ctx.status = 200;
  ctx.body = `
    <h2>With <code>"koa"</code> npm package</h2>
    <form action="/api/upload" enctype="multipart/form-data" method="post">
    <div>Text field title: <input type="text" name="title" /></div>
    <div>File: <input type="file" name="koaFiles" multiple="multiple" /></div>
    <input type="submit" value="Upload" />
    </form>
  `;
});

app.use((ctx) => {
  console.log('The next middleware is called');
  console.log('Results:', ctx.state);
});

app.listen(3000, () => {
  console.log('Server listening on http://localhost:3000 ...');
});

Benchmarks

The benchmark is quite old, from the old codebase. But maybe quite true though. Previously the numbers was around ~500 mb/sec. Currently with moving to the new Node.js Streams API it's faster. You can clearly see the differences between the Node versions.

_No

Related Skills

View on GitHub
GitHub Stars7.2k
CategoryOperations
Updated6d ago
Forks688

Languages

JavaScript

Security Score

100/100

Audited on Mar 17, 2026

No findings