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] -->…
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. 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 and available as
part of the [Tidelift Subscription][tidelift-url] for professional grade
assurances, enhanced support and security.
Learn more.
_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
- [Fast (~900-2500 mb/sec)](#benchmarks) & streaming multipart parser
- Automatically writing file uploads to disk (optional, see
options.fileWriteStreamHandler](#options))
- [Plugins API](#useplugin-plugin) - allowing custom parsers and plugins
- Low memory footprint
- Graceful error handling
- Very high test coverage
Install
This package is a dual ESM/commonjs package.
> [!NOTE]
> This project requires Node.js >= 20. Install it using yarn or npm. _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.
js
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(`
With Node.js "http" module
Text field title:
File:
`);
});
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
js
import express from "express";
import formidable from "formidable";
const app = express();
app.get("/", (req, res) => {
res.send(`
With "express" npm package
Text field title:
File:
`);
});
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._
js
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 = `
With "koa" npm package
Text field title:
File:
`;
});
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.
_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

API
Formidable / IncomingForm
All shown are equivalent.
_Please pass [options](#options) to the function/constructor, not by assigning
them to the instance form_
js
import formidable from "formidable";
const form = formidable(options);
Options
See it's defaults in [src/Formidable.js DEFAULT_OPTIONS](./src/Formidable.js)
(the DEFAULT_OPTIONS constant).
options.encoding{string} - default'utf-8'; sets encoding for
options.uploadDir{string} - defaultos.tmpdir(); the directory for
fs.rename().
options.keepExtensions{boolean} - defaultfalse; to include the
options.allowEmptyFiles{boolean} - defaultfalse; allow upload empty
options.minFileSize{number} - default1(1byte); the minium size of
options.maxFiles{number} - defaultInfinity;
options.maxFileSize{number} - default200 * 1024 * 1024(200mb);
options.maxTotalFileSize{number} - defaultoptions.maxFileSize;
options.maxFields{number} - default1000; limit the number of fields, set Infinity for unlimitedoptions.maxFieldsSize{number} - default20 * 1024 * 1024(20mb);
options.hashAlgorithm{string | false} - defaultfalse; include checksums calculated
options.fileWriteStreamHandler{function} - defaultnull, which by
options.filename{function} - defaultundefinedUse it to control
options.filter{function} - default function that always returns true.
options.createDirsFromUploads{boolean} - default false. If true, makes direct folder uploads possible. Use `to create a form to upload folders. Has to be used with the optionsoptions.uploadDirandoptions.filenamewhereoptions.filenamehas to return a string with the character/for folders to be created. The base will beoptions.uploadDir.
options.filename {function} function (name, ext, part, form) -> string
where part can be decomposed as
js
const { originalFilename, mimetype } = part;
_Note: If this size of combined fields, or size of some file is exceeded, an
'error' event is fired._
js
// The amount of bytes received for this form so far.
form.bytesReceived;
js
// The expected number of bytes in this form.
form.bytesExpected;
options.filter {function} function ({name, originalFilename, mimetype}) -> boolean
Behaves like Array.filter: Returning false will simply ignore the file and go to the next.
js
const options = {
filter: function ({ name, originalFilename, mimetype }) {
// keep only images
return mimetype && mimetype.includes("image");
},
};
Note: use an outside variable to cancel all uploads upon the first error
Note: use form.emit('error') to make form.parse error
js
let cancelUploads = false; // create variable at the same scope as form
const options = {
filter: function ({ name, originalFilename, mimetype }) {
// keep only images
const valid = mimetype && mimetype.includes("image");
if (!valid) {
form.emit("error", new formidableErrors.default("invalid type", 0, 400)); // optional make form.parse error
cancelUploads = true; //variable to make filter return false after the first problem
}
return valid && !cancelUploads;
},
};
.parse(request, ?callback)
Parses an incoming Node.js request containing form data. If callback is not provided a promise is returned.
js
const form = formidable({ uploadDir: __dirname });
form.parse(req, (err, fields, files) => {
console.log("fields:", fields);
console.log("files:", files);
});
// with Promise
const [fields, files] = await form.parse(req);
You may overwrite this method if you are interested in directly accessing the
multipart stream. Doing so will disable any 'field' / 'file' events
processing which would occur otherwise, making you fully responsible for
handling the processing.
About uploadDir, given the following directory structure
``
project-name
├── src
│ └── server.js
│
└── uploads
…
-
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.
JavaScript ★ 7.2k 2d agoExplain → -
.github ⑂
Policies and Guides
JavaScript ★ 1 2mo agoExplain →
No repos match these filters.