What is formidable?
The formidable npm package is a Node.js module for parsing form data, especially file uploads. It can handle multipart/form-data, which is used for uploading files through forms.
What are formidable's main functionalities?
File Upload
This code creates an HTTP server that listens for POST requests on the '/upload' path. It uses formidable to parse the incoming form data and handle file uploads.
const formidable = require('formidable');
const http = require('http');
http.createServer((req, res) => {
if (req.url === '/upload' && req.method.toLowerCase() === 'post') {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) {
res.writeHead(500, { 'content-type': 'text/plain' });
res.end('Error parsing the files');
return;
}
res.writeHead(200, { 'content-type': 'text/plain' });
res.write('Files uploaded successfully:\n');
res.end(JSON.stringify(files, null, 2));
});
}
}).listen(8080);
Form Field Parsing
This code snippet demonstrates how to use formidable to parse regular form fields (text inputs, selects, etc.) in addition to file uploads.
const formidable = require('formidable');
const http = require('http');
http.createServer((req, res) => {
if (req.url === '/submit' && req.method.toLowerCase() === 'post') {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) {
res.writeHead(500, { 'content-type': 'text/plain' });
res.end('Error parsing the form fields');
return;
}
res.writeHead(200, { 'content-type': 'text/plain' });
res.write('Form fields submitted:\n');
res.end(JSON.stringify(fields, null, 2));
});
}
}).listen(8080);
File Upload Progress
This example shows how to track the progress of a file upload using formidable's 'progress' event, which provides the bytes received and the total bytes expected.
const formidable = require('formidable');
const http = require('http');
http.createServer((req, res) => {
if (req.url === '/upload' && req.method.toLowerCase() === 'post') {
const form = new formidable.IncomingForm();
form.on('progress', (bytesReceived, bytesExpected) => {
console.log(`Progress: ${bytesReceived}/${bytesExpected}`);
});
form.parse(req, (err, fields, files) => {
// Handle file upload and response
});
}
}).listen(8080);
Other packages similar to formidable
multer
Multer is another popular Node.js middleware for handling multipart/form-data, which is primarily used for uploading files. It is built on top of busboy for maximum efficiency. Unlike formidable, multer is specifically designed for use with Express applications and includes more options for file storage and manipulation.
busboy
Busboy is a low-level Node.js module for parsing multipart/form-data request bodies. Formidable is actually built on top of busboy. Busboy is faster and more efficient but requires more setup and manual handling compared to formidable, which provides a higher-level API.
multiparty
Multiparty is a Node.js module for parsing multipart/form-data requests. It is similar to formidable in terms of functionality but has a different API and is known for being more memory efficient, as it streams files to disk instead of buffering them in memory.
formidable@next
v4 preparations. Modern multipart form-data parser for Node.js, Bun, Deno, Cloudflare, and the
browser.
[!CAUTION]
For older Node versions like v14, v15 and v16 you have to use the web-streams-polyfill
in your
project. Minimum required version is the first Node.js v14 LTS release, v14.15.0
(Fermium).
install
npm i formidable@next
Example
import {
parseMultipartRequest,
parseMultipart,
formidableDefaultOptions,
FormidableError,
FormidableOptions,
FormidablePart,
} from 'formidable';
async function formidable(req: Request, options?: FormidableOptions) {
try {
await parseMultipartRequest(req, options, async (part: FormidablePart) => {
if (part.isFile()) {
console.log('file', part.name, part.filename, part.toString());
} else {
console.log('field', part.name, await part.text());
}
});
} catch (er: FormidableError) {
switch (er.code) {
case 'ERR_INVALID_INPUT':
console.error(er.message);
break;
case 'ERR_BODY_CONSUMED':
console.error(er.message);
break;
case 'ERR_FAILED_TO_PARSE_TEXT':
console.error(er.message);
break;
case 'ERR_FAILED_TO_PARSE_JSON':
console.error(er.message);
break;
case 'ERR_NO_BOUNDARY':
console.error(er.message);
break;
case 'ERR_MAX_FILENAME_SIZE':
console.error(er.message);
break;
case 'ERR_MAX_FILE_SIZE':
console.error(er.message);
break;
case 'ERR_MAX_FILE_KEY_SIZE':
console.error(er.message);
break;
case 'ERR_MAX_FIELD_SIZE':
console.error(er.message);
break;
case 'ERR_MAX_FIELD_KEY_SIZE':
console.error(er.message);
break;
case 'ERR_MAX_HEADER_SIZE':
console.error(er.message);
break;
case 'ERR_MAX_HEADER_KEY_SIZE':
console.error(er.message);
break;
case 'ERR_MAX_HEADER_VALUE_SIZE':
console.error(er.message);
break;
case 'ERR_MAX_ALL_HEADERS_SIZE':
console.error(er.message);
break;
}
}
}
Usage in Node.js v14 and v16
[!CAUTION]
Minimum required version is the first Node.js v14 LTS release, v14.15.0
(Fermium).
It bundles the headers-polyfill
for compatibility with older Node.js versions. For Node.js v14 it
bundles both; for Node.js v16 you have to import 'web-streams-polyfill/polyfill';
for ESM, or
modules require('web-streams-polyfill/ponyfill');
for CJS
import 'web-streams-polyfill/polyfill';
import { createServer } from 'node:http';
import { parseMultipartRequest } from 'formidable';
const server = createServer((req, res) => {
if (req.method === 'POST') {
await parseMultipartRequest(
req,
{
maxFileSize: 1 * 1024 * 1024,
maxFilenameSize: 1000,
maxFileKeySize: 1000,
maxFieldKeySize: 1000,
},
async (part) => {
console.log('part:', part.toString());
},
);
} else {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
}
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});
Usage in modern Node.js and other runtimes
You can either use the above helper formidable
function or the parseMultipartRequest
directly,
works on any Fetch/Request/Response API compatible runtime.
- for Node.js v18+, you can use the
formidable
import directly
- for Bun, Deno, Cloudflare, and the browser, you can use the
formidable
import too
import { parseMultipartRequest } from 'formidable';
export default {
async fetch(req: Request) {
if (req.method === 'POST') {
await parseMultipartRequest(
req,
{
maxFileSize: 1 * 1024 * 1024,
maxFilenameSize: 1000,
maxFileKeySize: 1000,
maxFieldKeySize: 1000,
},
async (part: FormidablePart) => {
console.log('part:', part.toString());
},
);
return new Response('ok');
}
return new Response('Hello World, try POST request', {
status: 200,
headers: {
'Content-Type': 'text/plain',
},
});
},
};
Options
maxAllHeadersSize
{number} - size for all headers combined, (default: 8kb)
maxHeaderKeySize
{number} - size of the key per each header, (default: 255)
maxHeaderValueSize
{number} - size of the value of each header, (default: 1kb)
maxHeaderSize
{number} - size of key + value of each header, (default: 2kb)
maxFilenameSize
{number} - size of the file original filename, (default: 255)
maxFileKeySize
{number} - size of the key of file fields, (default: 255)
maxFileSize
{number} - size of each file, (default: 100mb)
maxFieldKeySize
{number} - size of the key of text fields, (default: 255)
maxFieldSize
{number} - size of each text field value, (default: 100kb)