How to Handle File Uploads in Node.js with Formidable
The Formidable NPM package is a widely used library for handling file uploads in Node.js. This guide demonstrates its use through a simple project.
Below is a preview of the application you will build:

A basic Node.js file upload application built with the Formidable NPM package
Create a New Project Directory
Section titled “Create a New Project Directory”mkdir codesweetly-form-001Afterward, navigate to your project directory using the command line.
cd path/to/codesweetly-form-001Create a package.json File
Section titled “Create a package.json File”Once you’re in the app’s directory, use NPM to create a package.json file for your project.
npm init -yOpen the package.json file and delete the main field.
Also, change the type field to module so you can use ECMAScript modules in this tutorial.
{ "scripts": { "start": "node console.js", "test": "echo "Error: no test specified" && exit 1" }, "type": "module"}Create a Form for Uploading Files
Section titled “Create a Form for Uploading Files”Create an ES Module for your project.
touch form-server.jsNext, open your new module and set up the form for file uploads.
import { createServer } from "node:http";
const server = createServer((req, res) => { if (req.url === "/") { res.writeHead(200, { "Content-Type": "text/html" }); res.write( '<div style="margin: 100px auto; font-family: Arial, sans-serif; line-height: 1.5; color: #333; max-width: 600px;">', ); res.write( '<form action="upload-file" method="post" enctype="multipart/form-data" style="border: 1px solid #ccc; padding: 30px 50px; border-radius: 5px; background-color: #f9f9f9; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);">', ); res.write( '<label style="display: block; margin-bottom: 30px;"><strong style="display: block; margin-bottom: 5px;">Title</strong> <input style="width: 100%; padding: 5px; border: 1px solid #ccc; border-radius: 3px;" type="text" name="title" /></label>', ); res.write( '<input type="file" name="uploadedFile" style="display: block; margin-bottom: 20px;" />', ); res.write( '<button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 3px; cursor: pointer;">Upload File</button>', ); res.write("</form>"); res.end("</div>"); }});
server.listen(3000, "localhost", () => { console.log("Server running at http://localhost:3000/");});Here’s what the code above does:
- Imports the
createServerAPI from Node’shttplibrary into theform-server.jsES Module. - Creates and sends a form element to the client when the server receives requests to the root path (
/). - Configures the port and hostname where the server listens for client requests.
Install the Formidable Package
Section titled “Install the Formidable Package”Run the following command in your terminal to install the formidable NPM package:
npm install formidableUse the Formidable Module in Your Node.js Application
Section titled “Use the Formidable Module in Your Node.js Application”Add the formidable module and use it to parse form data sent from the client to the server.
import { createServer } from "node:http";import formidable from "formidable";
const server = createServer((req, res) => { if (req.url === "/") { res.writeHead(200, { "Content-Type": "text/html" }); res.write( '<div style="margin: 100px auto; font-family: Arial, sans-serif; line-height: 1.5; color: #333; max-width: 600px;">', ); res.write( '<form action="upload-file" method="post" enctype="multipart/form-data" style="border: 1px solid #ccc; padding: 30px 50px; border-radius: 5px; background-color: #f9f9f9; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);">', ); res.write( '<label style="display: block; margin-bottom: 30px;"><strong style="display: block; margin-bottom: 5px;">Title</strong><input style="width: 100%; padding: 5px; border: 1px solid #ccc; border-radius: 3px;" type="text" name="title" /></label>', ); res.write( '<input type="file" name="uploadedFile" style="display: block; margin-bottom: 20px;" />', ); res.write( '<button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 3px; cursor: pointer;">Upload File</button>', ); res.write("</form>"); res.end("</div>"); }
if (req.url === "/upload-file" && req.method.toLowerCase() === "post") { const form = formidable(); form.parse(req, (err, fields, files) => { if (err) { res.writeHead(err.httpCode || 400, { "Content-Type": "text/plain" }); return res.end(`${err}`); } console.log("Title:", fields.title); console.log("Uploaded file:", files.uploadedFile); res.writeHead(200, { "Content-Type": "text/plain" }); res.end("Uploaded file successfully!"); }); }});
server.listen(3000, "localhost", () => { console.log("Server running at http://localhost:3000/");});Here’s what the code above does:
- Imports the
createServerAPI from Node’shttplibrary to theform-server.jsES Module. - Creates and sends a form to the client when the server receives a request to the root path (
/). - Uses the formidable module to parse the client’s POST request to the
/upload-fileURL. - Configures the port and hostname where the server listens for client requests.
Run Your Application
Section titled “Run Your Application”Now that your form is set up and the server is configured, you can run the application.
node --watch form-server.jsnode: The command for running Node.js scripts or the REPL.--watch: The flag for activating Node’s watch mode.form-server.js: The JavaScript file you want Node to run.
You can also add the command to the "scripts" field of your project’s package.json file:
{ "scripts": { "start": "node --watch form-server.js", "test": "echo \"Error: no test specified\" && exit 1" }}By so doing, you can run your JavaScript program from your terminal like this:
npm run startThe parse() method is an important part of the formidable API. The next section explains how it works.
What Is the Formidable parse() Method?
Section titled “What Is the Formidable parse() Method?”The parse() method lets you process a client request that contains form data. You can use it with a callback or as a promise.
The callback-based parse() method
Section titled “The callback-based parse() method”The callback-based parse() method takes two arguments. Here’s how it looks:
import formidable from "formidable";
const form = formidable();
form.parse(request, callback);request: The client’s request (the http.IncomingMessage object)callback: A function that handles the form data.
The callback function has three parameters. Here’s the syntax:
function (error, fields, files) { ... }error: An object for handling any errorsparse()finds while processing the form data.fields: An object containing the form fields’ names and values.files: An object containing details about the uploaded files.
Here’s an example:
import { createServer } from "node:http";import formidable from "formidable";
const server = createServer((req, res) => { if (req.url === "/") { res.writeHead(200, { "Content-Type": "text/html" }); res.write( '<div style="margin: 100px auto; font-family: Arial, sans-serif; line-height: 1.5; color: #333; max-width: 600px;">', ); res.write( '<form action="upload-file" method="post" enctype="multipart/form-data" style="border: 1px solid #ccc; padding: 30px 50px; border-radius: 5px; background-color: #f9f9f9; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);">', ); res.write( '<label style="display: block; margin-bottom: 30px;"><strong style="display: block; margin-bottom: 5px;">Title</strong><input style="width: 100%; padding: 5px; border: 1px solid #ccc; border-radius: 3px;" type="text" name="title" /></label>', ); res.write( '<input type="file" name="uploadedFile" style="display: block; margin-bottom: 20px;" />', ); res.write( '<button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 3px; cursor: pointer;">Upload File</button>', ); res.write("</form>"); res.end("</div>"); }
if (req.url === "/upload-file" && req.method.toLowerCase() === "post") { const form = formidable(); form.parse(req, (err, fields, files) => { if (err) { res.writeHead(err.httpCode || 400, { "Content-Type": "text/plain" }); return res.end(`${err}`); } console.log("Title:", fields.title); console.log("Uploaded file:", files.uploadedFile); res.writeHead(200, { "Content-Type": "text/plain" }); res.end("Uploaded file successfully!"); }); }});
server.listen(3000, "localhost", () => { console.log("Server running at http://localhost:3000/");});The code above uses the callback-based parse() method to process the form’s data.
The promise-based version of the parse() method
Section titled “The promise-based version of the parse() method”The promise-based parse() method takes just one argument. Here’s how it looks:
import formidable from "formidable";
const form = formidable();
const [fields, files] = await form.parse(request);fields: An object containing the form fields’ names and values.files: An object containing details about the uploaded files.request: The client’s request (the http.IncomingMessage object)
Here’s an example:
import { createServer } from "node:http";import formidable from "formidable";
const server = createServer((req, res) => { if (req.url === "/") { res.writeHead(200, { "Content-Type": "text/html" }); res.write( '<div style="margin: 100px auto; font-family: Arial, sans-serif; line-height: 1.5; color: #333; max-width: 600px;">', ); res.write( '<form action="upload-file" method="post" enctype="multipart/form-data" style="border: 1px solid #ccc; padding: 30px 50px; border-radius: 5px; background-color: #f9f9f9; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);">', ); res.write( '<label style="display: block; margin-bottom: 30px;"><strong style="display: block; margin-bottom: 5px;">Title</strong><input style="width: 100%; padding: 5px; border: 1px solid #ccc; border-radius: 3px;" type="text" name="title" /></label>', ); res.write( '<input type="file" name="uploadedFile" style="display: block; margin-bottom: 20px;" />', ); res.write( '<button type="submit" style="background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 3px; cursor: pointer;">Upload File</button>', ); res.write("</form>"); res.end("</div>"); }
if (req.url === "/upload-file" && req.method.toLowerCase() === "post") { async function processForm() { try { const form = formidable(); const [fields, files] = await form.parse(req); console.log("Title:", fields.title); console.log("Uploaded file:", files.uploadedFile); res.writeHead(200, { "Content-Type": "text/plain" }); res.end("Uploaded file successfully!"); } catch (err) { res.writeHead(err.httpCode || 400, { "Content-Type": "text/plain" }); res.end(`${err}`); console.error(err); } } processForm(); }});
server.listen(3000, "localhost", () => { console.log("Server running at http://localhost:3000/");});The code above uses the promise-based parse() method to process the form’s data.
By default, formidable saves uploaded files in your computer’s temporary folder. You can change this setting if needed. The following section explains how.
How to Specify Where Formidable Should Save the Uploaded Files
Section titled “How to Specify Where Formidable Should Save the Uploaded Files”The formidable() method takes an object that lets you specify the directory for saving uploaded files.
Here’s the syntax:
import formidable from "formidable";
const form = formidable({ uploadDir: "./folder/to/save/uploads" });Here’s an example:
import formidable from "formidable";
const form = formidable({ uploadDir: "./" });The code above tells Formidable to save uploaded files in the current directory.
Here’s another example:
import formidable from "formidable";
const form = formidable({ uploadDir: "./uploads" });The code above tells Formidable to save uploaded files in the uploads folder inside the current directory.