Need help with formidable?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

6.0K Stars 653 Forks MIT License 638 Commits 68 Opened issues


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.

Services available


Need anything else?

Contributors list

npm formidable package logo

formidable npm version MIT license Libera Manifesto Twitter

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

Code style codecoverage linux build status windows build status macos build status

If you have any how-to kind of questions, please read the Contributing Guide and Code of Conduct documents.
For bugs reports and feature requests, please create an issue or ping @tunnckoCore at Twitter.

Conventional Commits Minimum Required Nodejs Tidelift Subcsription Buy me a Kofi Renovate App Status Make A Pull Request

This project is semantically versioned and available as part of the Tidelift Subscription for professional grade assurances, enhanced support and security. Learn more.

The maintainers of

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.

Status: Maintained npm version

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.

Note: The github

branch is a "canary" branch - try it with
npm i [email protected]
. Do not expect (for now) things from it to be inside the
"dist-tag" in the Npm. The
[email protected]
is the
version and probably it will be the last

Note: v2 is coming soon!



This project requires

Node.js >= 10.13
. Install it using yarn or npm.
We highly recommend to use Yarn when you think to contribute to this project.
npm install formidable
# or the canary version
npm install [email protected]

or with Yarn v1/v2

yarn add formidable
# or the canary version
yarn add [email protected]

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



For more examples look at the


with Node.js http module

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


const http = require('http');
const formidable = require('formidable');

const server = http.createServer((req, res) => { if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') { // parse a file upload const form = formidable({ multiples: true });

form.parse(req, (err, fields, files) => {
  if (err) {
    res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ fields, files }, null, 2));



// show a file upload form res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(`

With Node.js "http" module

Text field title:

`); });

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

const express = require('express');
const formidable = require('formidable');

const app = express();

app.get('/', (req, res) => { res.send(`

With "express" npm package

Text field title:

`); });'/api/upload', (req, res, next) => { const form = formidable({ multiples: true });

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

manually as shown below or through the koa-better-body package which is using
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

which is Node.js's Request, and NOT the
which is Koa's Request object - there is a difference.

const Koa = require('koa');
const formidable = require('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({ multiples: true });

// 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) {

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


// show a file upload form ctx.set('Content-Type', 'text/html'); ctx.status = 200; ctx.body = `

With "koa" npm package

Text field title:

`; });

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 ...'); });


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.

Note: a lot better benchmarking could and should be done in future.

Benchmarked on 8GB RAM, Xeon X3440 (2.53 GHz, 4 cores, 8 threads)

~/github/node-formidable master
❯ nve --parallel 8 10 12 13 node benchmark/bench-multipart-parser.js

⬢ Node 8

1261.08 mb/sec

⬢ Node 10

1113.04 mb/sec

⬢ Node 12

2107.00 mb/sec

⬢ Node 13

2566.42 mb/sec

benchmark January 29th, 2020


Formidable / IncomingForm

All shown are equivalent.

Please pass

to the function/constructor, not by assigning them to the instance

const formidable = require('formidable');
const form = formidable(options);

// or const { formidable } = require('formidable'); const form = formidable(options);

// or const { IncomingForm } = require('formidable'); const form = new IncomingForm(options);

// or const { Formidable } = require('formidable'); const form = new Formidable(options);


See it's defaults in src/Formidable.js DEFAULT_OPTIONS (the

  • options.encoding
    {string} - default
    ; sets encoding for incoming form fields,
  • options.uploadDir
    {string} - default
    ; the directory for placing file uploads in. You can move them later by using
  • options.keepExtensions
    {boolean} - default
    ; to include the extensions of the original files or not
  • options.allowEmptyFiles
    {boolean} - default
    ; allow upload empty files
  • options.minFileSize
    {number} - default
    (1byte); the minium size of uploaded file.
  • options.maxFileSize
    {number} - default
    200 * 1024 * 1024
    (200mb); limit the size of uploaded file.
  • options.maxFields
    {number} - default
    ; limit the number of fields, set 0 for unlimited
  • options.maxFieldsSize
    {number} - default
    20 * 1024 * 1024
    (20mb); limit the amount of memory all fields together (except files) can allocate in bytes.
  • options.hashAlgorithm
    {string | false} - default
    ; include checksums calculated for incoming files, set this to some hash algorithm, see crypto.createHash for available algorithms
  • options.fileWriteStreamHandler
    {function} - default
    , which by default writes to host machine file system every file parsed; The function should return an instance of a Writable stream that will receive the uploaded file data. With this option, you can have any custom behavior regarding where the uploaded file data will be streamed for. If you are looking to write the file uploaded in other types of cloud storages (AWS S3, Azure blob storage, Google cloud storage) or private file storage, this is the option you're looking for. When this option is defined the default behavior of writing the file in the host machine file system is lost.
  • options.multiples
    {boolean} - default
    ; when you call the
    method, the
    argument (of the callback) will contain arrays of files for inputs which submit multiple files using the HTML5
    attribute. Also, the
    argument will contain arrays of values for fields that have names ending with '[]'.
  • options.filename
    {function} - default
    Use it to control newFilename. Must return a string. Will be joined with options.uploadDir.
  • options.filter
    {function} - default function that always returns true. Use it to filter files before they are uploaded. Must return a boolean.

{function} function (name, ext, part, form) -> string

Note: If this size of combined fields, or size of some file is exceeded, an

event is fired.

// The amount of bytes received for this form so far.
// The expected number of bytes in this form.

{function} function ({name, originalFilename, mimetype}) -> boolean

Note: use an outside variable to cancel all uploads upon the first error

const options = {
  filter: function ({name, originalFilename, mimetype}) {
    // keep only images
    return mimetype && mimetype.includes("image");

.parse(request, callback)

Parses an incoming Node.js

containing form data. If
is provided, all fields and files are collected and passed to the callback.
const formidable = require('formidable');

const form = formidable({ multiples: true, uploadDir: __dirname });

form.parse(req, (err, fields, files) => { console.log('fields:', fields); console.log('files:', files); });

You may overwrite this method if you are interested in directly accessing the multipart stream. Doing so will disable any

events processing which would occur otherwise, making you fully responsible for handling the processing.


, given the following directory structure
├── src
│   └── server.js
└── uploads
    └── image.jpg

would be the same directory as the source file itself (src)

to put files in uploads.


would make the path relative to the current working directory. This would be the same if server.js is launched from src but not project-name.

will use default which is

Note: If the directory does not exist, the uploaded files are silently discarded. To make sure it exists:

import {createNecessaryDirectoriesSync} from "filesac";

const uploadPath = ${__dirname}/../uploads; createNecessaryDirectoriesSync(${uploadPath}/x);

In the example below, we listen on couple of events and direct them to the

listener, so you can do whatever you choose there, based on whether its before the file been emitted, the header value, the header name, on field, on file and etc.

Or the other way could be to just override the

as it's shown a bit later.
form.once('error', console.error);

form.on('fileBegin', (formname, file) => { form.emit('data', { name: 'fileBegin', formname, value: file }); });

form.on('file', (formname, file) => { form.emit('data', { name: 'file', formname, value: file }); });

form.on('field', (fieldName, fieldValue) => { form.emit('data', { name: 'field', key: fieldName, value: fieldValue }); });

form.once('end', () => { console.log('Done!'); });

// If you want to customize whatever you want... form.on('data', ({ name, key, value, buffer, start, end, formname, ...more }) => { if (name === 'partBegin') { } if (name === 'partData') { } if (name === 'headerField') { } if (name === 'headerValue') { } if (name === 'headerEnd') { } if (name === 'headersEnd') { } if (name === 'field') { console.log('field name:', key); console.log('field value:', value); } if (name === 'file') { console.log('file:', formname, value); } if (name === 'fileBegin') { console.log('fileBegin:', formname, value); } });

.use(plugin: Plugin)

A method that allows you to extend the Formidable library. By default we include 4 plugins, which esentially are adapters to plug the different built-in parsers.

The plugins added by this method are always enabled.

See src/plugins/ for more detailed look on default plugins.


param has such signature:
function(formidable: Formidable, options: Options): void;

The architecture is simple. The

is a function that is passed with the Formidable instance (the
across the README examples) and the options.

Note: the plugin function's

context is also the same instance.
const formidable = require('formidable');

const form = formidable({ keepExtensions: true });

form.use((self, options) => { // self === this === form console.log('woohoo, custom plugin'); // do your stuff; check src/plugins for inspiration });

form.parse(req, (error, fields, files) => { console.log('done!'); });

Important to note, is that inside plugin

MAY or MAY NOT be the same. General best practice is to always use the
, so you can later test your plugin independently and more easily.

If you want to disable some parsing capabilities of Formidable, you can disable the plugin which corresponds to the parser. For example, if you want to disable multipart parsing (so the src/parsers/Multipart.js which is used in src/plugins/multipart.js), then you can remove it from the

, like so
const { Formidable } = require('formidable');

const form = new Formidable({ hashAlgorithm: 'sha1', enabledPlugins: ['octetstream', 'querystring', 'json'], });

Be aware that the order MAY be important too. The names corresponds 1:1 to files in src/plugins/ folder.

Pull requests for new built-in plugins MAY be accepted - for example, more advanced querystring parser. Add your plugin as a new file in

folder (lowercased) and follow how the other plugins are made.


If you want to use Formidable to only handle certain parts for you, you can do something similar. Or see #387 for inspiration, you can for example validate the mime-type.

const form = formidable();

form.onPart = (part) => { part.on('data', (buffer) => { // do whatever you want here }); };

For example, force Formidable to be used only on non-file "parts" (i.e., html fields)

const form = formidable();

form.onPart = function (part) { // let formidable handle only non-file parts if (part.originalFilename === '' || !part.mimetype) { // used internally, please do not override! form._handlePart(part); } };


export interface File {
  // The size of the uploaded file in bytes.
  // If the file is still being uploaded (see `'fileBegin'` event),
  // this property says how many bytes of the file have been written to disk yet.
  file.size: number;

// The path this file is being written to. You can modify this in the 'fileBegin' event in // case you are unhappy with the way formidable generates a temporary path for your files. file.filepath: string;

// The name this file had according to the uploading client. file.originalFilename: string | null;

// calculated based on options provided file.newFilename: string | null;

// The mime type of this file, according to the uploading client. file.mimetype: string | null;

// A Date object (or null) containing the time this file was last written to. // Mostly here for compatibility with the W3C File API Draft. file.mtime: Date | null;

file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256' // If options.hashAlgorithm calculation was set, you can read the hex digest out of this var (at the end it will be a string) file.hash: string | object | null; }


This method returns a JSON-representation of the file, allowing you to

the file which is useful for logging and responding to requests.



Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.

form.on('progress', (bytesReceived, bytesExpected) => {});


Emitted whenever a field / value pair has been received.

form.on('field', (name, value) => {});


Emitted whenever a new file is detected in the upload stream. Use this event if you want to stream the file to somewhere else while buffering the upload on the file system.

form.on('fileBegin', (formName, file) => {
    // accessible here 
    // formName the name in the form () or http filename for octetstream
    // file.originalFilename http filename or null if there was a parsing error
    // file.newFilename generated hexoid or what options.filename returned
    // file.filepath default pathnme as per options.uploadDir and options.filename
    // file.filepath = CUSTOM_PATH // to change the final path


Emitted whenever a field / file pair has been received.

is an instance of
form.on('file', (formname, file) => {
    // same as fileBegin, except
    // it is too late to change file.filepath
    // file.hash is available if options.hash was used


Emitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call

if you want the request to continue firing

May have

form.on('error', (err) => {});


Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. After this event is emitted, an

event will follow. In the future there will be a separate 'timeout' event (needs a change in the node core).
form.on('aborted', () => {});


Emitted when the entire request has been received, and all contained files have finished flushing to disk. This is a great place for you to send your response.

form.on('end', () => {});

Ports & Credits


If the documentation is unclear or has a typo, please click on the page's

button (pencil icon) and suggest a correction. If you would like to help us fix a bug or add a new feature, please check our Contributing Guide. Pull requests are welcome!

Thanks goes to these wonderful people (emoji key):

Felix Geisendörfer

💻 🎨 🤔 📖

Charlike Mike Reagent

🐛 🚇 🎨 💻 📖 💡 🤔 🚧 ⚠️


💻 ⚠️ 💬 🐛

Walle Cyril

💬 🐛 💻 💵 🤔 🚧


💬 🐛 💻 🚧


💬 🐛 💻


💬 🐛 💻 🤔 🚧

Dylan Piercey


Adam Dobrawy

🐛 📖



Jesse Feng


Nathanael Demacon

💬 💻 👀



Gabriel Petrovay

🐛 💻

Philip Woods

💻 🤔

Dmitry Ivonin


Claudio Poli


From a Felix blog post:

  • Sven Lito for fixing bugs and merging patches
  • egirshov for contributing many improvements to the node-formidable multipart parser
  • Andrew Kelley for also helping with fixing bugs and making improvements
  • Mike Frey for contributing JSON support


Formidable is licensed under the MIT License.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.