File uploads are a common feature in modern web applications.
For example, users may upload profile pictures, documents, resumes, product images, videos, or other files. However, handling files is different from processing normal JSON data in a Node.js application.
This is where Multer becomes useful.
Multer is a middleware for Node.js and Express that helps applications handle multipart/form-data, which is commonly used when users upload files through HTML forms or HTTP requests.
In this article, we’ll explain what Multer is, how it works, why it is used, and how to upload files using Multer in Node.js and Express.
What Is Multer?
Multer is a Node.js middleware used for handling file uploads.
It is mainly designed to process requests that use:
multipart/form-data
This content type is commonly used when a request contains files.
For example, when a user selects an image and submits a form:
User
↓
Selects File
↓
Browser Creates multipart/form-data Request
↓
Express Server
↓
Multer Processes File
↓
Application Handles File
Without middleware designed for file uploads, Express does not automatically handle uploaded files in the same way it handles regular JSON request bodies.
Therefore, Multer helps parse the incoming request and makes uploaded files available to your application.
Why Do We Need Multer?
Suppose you have an Express application that accepts JSON data.
A typical request may look like this:
{
"name": "John",
"email": "john@example.com"
}
Express middleware such as:
app.use(express.json());
can parse JSON request bodies.
However, file uploads usually use a different format.
For example:
multipart/form-data
A file upload request may contain:
Name: John
Email: john@example.com
Profile Image: profile.jpg
Therefore, a file upload middleware is needed to process the uploaded file.
Multer handles this format and separates the files from other form data.
How Does Multer Work?
The basic Multer workflow looks like this:
User
↓
Selects File
↓
Sends multipart/form-data Request
↓
Express Route
↓
Multer Middleware
↓
Processes File
↓
Stores or Provides File Data
↓
Route Handler
Multer runs before your route handler.
It processes the incoming request and adds information to the request object.
For example:
req.file
or:
req.files
The route handler can then access information about the uploaded file.
Installing Multer
First, install Multer in your Node.js project:
npm install multer
Then import it into your Express application:
const multer = require("multer");
If you are using ES modules:
import multer from "multer";
Basic Multer Example
Let’s create a simple Express application.
const express = require("express");
const multer = require("multer");
const app = express();
const upload = multer({
dest: "uploads/"
});
app.post("/upload", upload.single("file"), (req, res) => {
console.log(req.file);
res.send("File uploaded successfully");
});
app.listen(3000);
The request flow is:
POST /upload
↓
Multer Receives File
↓
File Stored in uploads/
↓
req.file Created
↓
Route Handler Runs
In this example:
upload.single("file")
means the application expects one uploaded file with the field name:
file
What Is multipart/form-data?
To understand Multer properly, you need to understand multipart/form-data.
When a request only contains normal data, JSON is often used.
For example:
{
"username": "manjeet"
}
However, JSON is not designed to directly send binary files in the same way as a typical file upload form.
Therefore, browsers commonly use:
multipart/form-data
This format allows a request to contain multiple parts.
For example:
Part 1 → Username
Part 2 → Email
Part 3 → Profile Image
Multer processes these parts and makes the data available in the Express request.
How Multer Adds Data to req
Multer can add two types of information to the request object.
Regular form data is available through:
req.body
Uploaded file information can be available through:
req.file
or:
req.files
For example:
multipart/form-data Request
↓
Multer
↙ ↘
req.body req.file
This separation makes it easier to work with both text fields and uploaded files.
Uploading a Single File
To upload one file, use:
upload.single("file")
Example:
app.post("/upload", upload.single("file"), (req, res) => {
console.log(req.file);
res.json({
message: "File uploaded successfully"
});
});
The HTML input might look like:
<input type="file" name="file">
The field name must match:
HTML Input → file
Multer → upload.single("file")
Uploading Multiple Files
Sometimes users need to upload more than one file.
For example:
- Product images
- Multiple documents
- Photo galleries
Multer provides:
upload.array()
Example:
app.post(
"/upload",
upload.array("files", 5),
(req, res) => {
console.log(req.files);
res.send("Files uploaded successfully");
}
);
In this example:
Field Name → files
Maximum Files → 5
The uploaded files are available through:
req.files
Uploading Different Types of Files
An application may need multiple file fields.
For example:
Profile Picture
Resume
Multer provides:
upload.fields()
Example:
app.post(
"/upload",
upload.fields([
{
name: "profileImage",
maxCount: 1
},
{
name: "resume",
maxCount: 1
}
]),
(req, res) => {
console.log(req.files);
res.send("Files uploaded successfully");
}
);
This approach is useful when different file fields have different purposes.
Multer Storage Options
Multer supports different storage approaches.
Two common options are:
- Disk storage
- Memory storage
Disk Storage
Disk storage saves uploaded files to the server’s file system.
For example:
User Upload
↓
Multer
↓
Server Storage
↓
uploads/
You can configure the destination and file name.
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "uploads/");
},
filename: (req, file, cb) => {
cb(null, Date.now() + "-" + file.originalname);
}
});
const upload = multer({
storage: storage
});
This gives more control over where files are stored.
Memory Storage
Memory storage keeps uploaded files in memory instead of immediately saving them to disk.
For example:
User Upload
↓
Multer
↓
Server Memory
↓
Process File
↓
Send to Another Storage Service
Example:
const storage = multer.memoryStorage();
const upload = multer({
storage: storage
});
The file can then be available as a buffer.
This approach can be useful when the application needs to process a file before storing it elsewhere.
However, large uploads can consume significant memory. Therefore, file size limits are important.
Understanding req.file
When using:
upload.single("file")
Multer adds file information to:
req.file
The information may include details such as:
filename
originalname
mimetype
size
path
For example:
console.log(req.file);
The application can then use this information for further processing.
Understanding req.files
When uploading multiple files, Multer uses:
req.files
For example:
upload.array("images", 5)
The application can then access the uploaded files:
console.log(req.files);
The exact structure depends on whether array() or fields() is used.
File Filtering With Multer
Applications should not accept every type of file.
For example, if users can upload profile pictures, the application may only accept image files.
Multer provides a fileFilter option.
Example:
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (file.mimetype === "image/jpeg") {
cb(null, true);
} else {
cb(new Error("Only JPEG images are allowed"), false);
}
}
});
The flow becomes:
File Upload
↓
Check File
↓
Allowed?
↙ ↘
No Yes
↓ ↓
Reject Process
However, MIME type checks alone should not be treated as complete security validation. Additional server-side file validation may be needed for sensitive applications.
Setting File Size Limits
Large files can consume server resources.
Therefore, Multer allows developers to define limits.
Example:
const upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024
}
});
This example sets a maximum file size of:
5 MB
The flow is:
Upload File
↓
Check Size
↓
Within Limit?
↙ ↘
No Yes
↓ ↓
Reject Continue
Server-side limits are important because client-side validation can be bypassed.
Handling Multer Errors
File uploads can fail for several reasons.
For example:
- File is too large
- Too many files
- Invalid file field
- Unexpected upload data
Therefore, applications should handle upload errors properly.
A simple example is:
app.post("/upload", (req, res) => {
upload.single("file")(req, res, (error) => {
if (error) {
return res.status(400).json({
message: error.message
});
}
res.json({
message: "File uploaded successfully"
});
});
});
Proper error handling improves both security and user experience.
Multer and Cloud Storage
In production applications, storing files directly on the application server may not always be the best option.
For example:
User
↓
Application
↓
Local Server Storage
A scalable architecture may use external storage:
User
↓
Application
↓
Multer
↓
Cloud Storage
For example, applications may upload files to:
- Object storage
- Cloud storage services
- Dedicated file storage systems
In this case, Multer can help process the incoming upload before the application sends the file to the final storage location.
Multer With an Image Upload Workflow
Suppose users upload profile images.
A possible workflow is:
User Selects Image
↓
multipart/form-data
↓
Multer
↓
Validate File
↓
Check File Size
↓
Process Image
↓
Store Image
↓
Save Image Reference
↓
Database
The database usually stores information about the file rather than the file itself.
For example:
User
├── name
├── email
└── profileImageUrl
The actual file can remain in a dedicated storage system.
Common Multer Methods
Multer provides several useful upload methods.
upload.single()
Use this when the request contains one file.
upload.single("profileImage")
The file is available through:
req.file
upload.array()
Use this when the request contains multiple files with the same field name.
upload.array("images", 5)
The files are available through:
req.files
upload.fields()
Use this when the request contains multiple file fields.
upload.fields([
{ name: "avatar", maxCount: 1 },
{ name: "documents", maxCount: 3 }
]);
The files are available through:
req.files
upload.none()
Use this when processing multipart/form-data that contains no files.
upload.none()
This can be useful when an endpoint receives multipart form fields without file uploads.
Common Mistakes When Using Multer
Several common mistakes can cause problems.
1. Field Names Do Not Match
For example:
<input type="file" name="image">
but:
upload.single("file")
These names must match.
Correct:
HTML → image
Multer → image
2. Forgetting File Size Limits
Without limits, large uploads can consume server resources.
Always define reasonable limits based on your application’s requirements.
3. Trusting File Extensions
Checking only:
.jpg
.png
.pdf
is not enough for sensitive applications.
A file extension can be changed.
Therefore, applications should use multiple validation layers.
4. Using User File Names Directly
Users may upload files with the same name or unexpected names.
Generate unique file names on the server instead.
5. Using Memory Storage for Large Files
Memory storage can be useful.
However, large files can consume significant server memory.
Therefore, use limits and choose the storage strategy carefully.
Multer Security Best Practices
When using Multer, follow these security practices.
Accept Only Required File Types
Use an allowlist of accepted formats.
For example:
JPEG
PNG
WebP
Set File Size Limits
Prevent unexpectedly large uploads.
Generate Server-Side File Names
Do not rely on user-provided file names.
Validate Files on the Server
Do not rely only on browser-side validation.
Store Files Securely
Avoid placing untrusted uploads where they could be treated as executable application code.
Scan Files When Necessary
Applications that accept documents or files from many users may require malware scanning.
Use Authentication and Authorization
Only allow appropriate users to upload files.
Multer vs express.json()
These two middleware tools solve different problems.
express.json()
Used for:
application/json
Example:
app.use(express.json());
It helps parse JSON request bodies.
Multer
Used for:
multipart/form-data
Example:
const upload = multer();
It helps process file uploads and multipart form data.
A Simple Multer Architecture
The overall architecture may look like this:
Frontend
↓
File Selected
↓
multipart/form-data Request
↓
Express Server
↓
Multer Middleware
↓
Validation
↓
Storage
↓
Database Stores File Reference
Each part has a different responsibility.
When Should You Use Multer?
Multer is useful when building an Express or Node.js application that accepts:
- Profile images
- Product images
- Documents
- Resumes
- PDFs
- Multiple images
- User-generated files
It is particularly useful when your application receives files using multipart/form-data.
Final Thoughts: What Is Multer?
Multer is a middleware that helps Express and Node.js applications handle file uploads.
It processes multipart/form-data requests and makes uploaded file information available through:
req.file
or:
req.files
Depending on your configuration, files can be stored on disk, kept temporarily in memory, or processed before being sent to another storage system.
Conclusion
File uploads are an important part of many modern web applications.
However, handling uploaded files requires more than simply accepting data from a form.
Multer provides a convenient way to process multipart/form-data requests in Express applications. It supports single-file uploads, multiple files, multiple file fields, file size limits, filtering, and different storage strategies.
The basic workflow is:
User Uploads File → Multer Processes Request → Application Validates File → File Is Stored or Processed
When combined with proper validation, file size limits, secure storage, authentication, and access controls, Multer can help developers build reliable file upload features in Node.js applications.




