How to Handle File Uploads in Node.js with Multer
Handling file uploads is a fundamental requirement for many modern web applications, whether you are accepting user profile pictures, documents, or media files. This article provides a straightforward, step-by-step guide on how to implement secure and efficient file uploads in a Node.js environment using the popular Multer middleware. You will learn how to install the necessary packages, configure storage options, restrict file sizes and types, and handle errors effectively in an Express application.
Prerequisites and Installation
To manage file uploads in Node.js, you need an Express application
and the Multer middleware. Multer is a body-parser middleware that
facilitates uploading files by handling
multipart/form-data.
Initialize your project and install the required packages using npm:
npm init -y
npm install express multerBasic Configuration and Disk Storage
To maintain control over where files are saved and how they are named, you should configure Multer’s disk storage engine. This prevents files from being saved with random names and no extensions.
Create a file named server.js and set up the basic
storage configuration:
const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const PORT = 3000;
// Configure storage destination and filename
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/'); // Ensure this folder exists in your project root
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
}
});Adding File Filters and Limits
For security and performance, it is critical to limit the file size and restrict the allowed file types (such as allowing only images).
// File filter to allow only specific formats (e.g., JPEG, PNG, GIF)
const fileFilter = (req, file, cb) => {
const allowedTypes = /jpeg|jpg|png|gif/;
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = allowedTypes.test(file.mimetype);
if (extname && mimetype) {
return cb(null, true);
} else {
cb(new Error('Only images (jpeg, jpg, png, gif) are allowed!'));
}
};
// Initialize Multer with storage, limits, and filter
const upload = multer({
storage: storage,
limits: { fileSize: 2 * 1024 * 1024 }, // Limit size to 2MB
fileFilter: fileFilter
});Creating the Upload Routes
With Multer configured, you can now create routes to handle both single and multiple file uploads.
Single File Upload
Use upload.single('fieldname') for a single file upload.
The file details will be available in req.file.
app.post('/upload-single', upload.single('profilePic'), (req, res) => {
if (!req.file) {
return res.status(400).send('No file uploaded.');
}
res.send({
message: 'File uploaded successfully!',
file: req.file
});
});Multiple Files Upload
Use upload.array('fieldname', maxCount) to handle
multiple files. The file details will be available in
req.files.
app.post('/upload-multiple', upload.array('photos', 5), (req, res) => {
if (!req.files || req.files.length === 0) {
return res.status(400).send('No files uploaded.');
}
res.send({
message: `${req.files.length} files uploaded successfully!`,
files: req.files
});
});Handling Upload Errors
It is essential to handle errors gracefully, such as when a file exceeds the size limit or fails the validation filter. You can do this by using a custom Express error handler.
// Error handling middleware
app.use((err, req, res, next) => {
if (err instanceof multer.MulterError) {
// A Multer error occurred when uploading (e.g., file too large)
return res.status(400).json({ error: err.message });
} else if (err) {
// An unknown error or custom validation error occurred
return res.status(400).json({ error: err.message });
}
next();
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});