When a browser submits a form that includes a file input (<input type="file">), it sends the data with a special content type: multipart/form-data. The standard express.json() middleware cannot parse this format. You need a specialized tool, and the most popular one in the Express ecosystem is Multer.
Multer is a middleware for handling multipart/form-data, which is primarily used for uploading files. It adds a file or files object to the request object (req), containing information about the uploaded file(s).
1. Setting Up Multer
First, install multer in your project:
Bash
npm install multer
Next, you need to configure Multer. A common configuration is to tell it where to store the uploaded files on your server.
JavaScript
const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
// Configure storage for Multer
const storage = multer.diskStorage({
// destination is used to determine within which folder the uploaded files should be stored.
destination: function (req, file, cb) {
cb(null, './uploads/'); // Store files in an 'uploads' directory
},
// filename is used to determine what the file should be named inside the folder.
filename: function (req, file, cb) {
// Create a unique filename to avoid overwriting files
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
}
});
// Initialize Multer with the storage configuration
const upload = multer({ storage: storage });
The diskStorage engine gives you full control over storing files to disk.
2. Creating the Upload Route
Now you can use the upload instance as middleware in the route that will handle the file upload. Multer provides methods like .single(), .array(), and .fields() depending on your needs.
Let's create a route that accepts a single file upload from a form field named profileImage.
JavaScript
// The route will handle POST requests to /upload-profile
// 'upload.single('profileImage')' is the middleware.
// It looks for a file in a form field named 'profileImage'.
app.post('/upload-profile', upload.single('profileImage'), (req, res, next) => {
// If we get here, the file was successfully uploaded.
// Multer adds a 'file' object to the request.
if (!req.file) {
return res.status(400).send('No file was uploaded.');
}
console.log('File details:', req.file);
// You can also access form fields if they were sent
console.log('Body details:', req.body);
res.json({
message: 'File uploaded successfully!',
filename: req.file.filename,
path: req.file.path
});
});
// A simple error handler for Multer-specific errors
app.use((error, req, res, next) => {
if (error instanceof multer.MulterError) {
// A Multer error occurred when uploading.
return res.status(400).json({ message: 'File upload error', error: error.message });
}
// An unknown error occurred.
next(error);
});
app.listen(3000, () => console.log('Server is running on port 3000'));
When a file is successfully uploaded, req.file will contain metadata about the file, such as its original name, new filename, destination path, size, and MIME type. This allows your application to then process the file, for example, by saving a reference to it in a database.