- Express.js Basics
- Express.js HOME
- Express.js Introduction
- Express.js Installation
- Express.js Basic App
- Express.js Routing
- Basics Routing
- Route Parameters
- Handling Query Strings
- Router Middleware
- Middleware
- What is Middleware?
- Application-Level Middleware
- Router-Level Middleware
- Built-In Middleware
- Error-Handling Middleware
- Third-Party Middleware
- Express.js HTTP
- Handling GET Requests
- Handling POST Requests
- Handling PUT Requests
- Handling DELETE Requests
- Templating Engines
- Using Templating Engines
- Setting Up EJS
- Setting Up Handlebars
- Setting Up Pug
- Request/Response
- Request Object
- Response Object
- Handling JSON Data
- Handling Form Data
- Static Files
- Serving Static Files
- Setting Up Static Folders
- Managing Assets
- Express.js Advanced
- Middleware Stack
- CORS in Express.js
- JWT Authentication
- Session Handling
- File Uploads
- Error Handling
- Databases
- Express.js with MongoDB
- MongoDB CRUD Operations
- Express.js with MySQL
- MySQL CRUD Operations
- Deployment
- Deploying Express.js Apps to Heroku
- Deploying Express.js Apps to AWS
- Deploying Express.js Apps to Vercel
Express.js File Uploads
File uploads are a fundamental requirement for modern web applications. Whether you are building a profile picture uploader, a document management system, or a content management tool, your server needs a way to receive and process binary data. Express.js itself does not handle multipart/form-data (the format used for file uploads) out of the box. To handle this, we use Multer, a powerful middleware built specifically for handling file uploads in Node.js applications.
express.json() and express.urlencoded() parsers only handle text data. If you try to access a file through req.body without Multer, it will be undefined.
Key Features of File Uploads
- Multipart Parsing: Multer does the heavy lifting of parsing incoming requests and making file data available in a
req.fileorreq.filesobject. - Flexible Storage: You can choose to store files directly on your server's disk or keep them in memory as
Bufferobjects for immediate processing or cloud uploading. - Robust Validation: Protect your server by enforcing strict rules on file extensions, MIME types, and maximum file sizes.
- Filename Customization: Programmatically rename files to prevent naming collisions and to keep your storage organized.
Setting Up File Uploads in Express.js
Install multer Middleware
First, you need to add Multer to your project dependencies using npm or yarn.
npm install multer
Basic Configuration
Before handling requests, you must configure how Multer should store incoming files. Using diskStorage gives you full control over the destination folder and the naming convention.
const multer = require('multer');
const path = require('path');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
// Ensure this folder exists before uploading
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
// Create a unique filename using the current timestamp and original name
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, `${uniqueSuffix}${path.extname(file.originalname)}`);
}
});
const upload = multer({ storage });
Handling Single File Upload
For a single file (like an avatar update), use the upload.single() middleware. The string passed to it must match the name attribute of the file input in your HTML form.
app.post('/upload', upload.single('avatar'), (req, res) => {
// req.file contains information about the uploaded file
// req.body contains text fields, if any were sent
if (!req.file) {
return res.status(400).send('No file uploaded.');
}
res.send(`File saved as: ${req.file.filename}`);
});
req.file exists inside your route handler. If a user submits a form without a file, Multer won't throw an error, but req.file will be undefined.
Handling Multiple File Uploads
When users need to upload multiple documents or a gallery of images, use upload.array(). You can also set a limit on the number of files accepted.
// Accepts up to 5 files with the field name 'photos'
app.post('/upload-gallery', upload.array('photos', 5), (req, res) => {
// req.files is an array of file objects
const fileCount = req.files.length;
res.send(`${fileCount} files uploaded successfully.`);
});
Validating Uploaded Files
Security is paramount when allowing file uploads. You should always restrict the file types and sizes to prevent malicious files from filling up your disk or executing code.
const uploadWithValidation = multer({
storage,
limits: { fileSize: 2 * 1024 * 1024 }, // 2MB limit
fileFilter: (req, file, cb) => {
const allowedTypes = /jpeg|jpg|png|gif/;
const isMimeValid = allowedTypes.test(file.mimetype);
const isExtValid = allowedTypes.test(path.extname(file.originalname).toLowerCase());
if (isMimeValid && isExtValid) {
return cb(null, true);
}
cb(new Error('Only image files (jpg, png, gif) are allowed!'));
}
});
fileSize limit. Allowing unlimited file sizes makes your server vulnerable to Denial of Service (DoS) attacks where an attacker fills your storage or crashes your process with massive files.
Serving Uploaded Files
To make your uploaded files accessible via a URL (e.g., for displaying an image in a browser), use Express's static middleware.
app.use('/public/uploads', express.static('uploads'));
// A file in 'uploads/my-pic.jpg' will be accessible at 'http://localhost:3000/public/uploads/my-pic.jpg'
Complete Example
Here is a production-ready structure for a basic Express file upload server.
const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
// 1. Configure Storage
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
cb(null, `user-${Date.now()}${path.extname(file.originalname)}`);
}
});
// 2. Initialize Multer
const upload = multer({
storage,
limits: { fileSize: 5 * 1024 * 1024 } // 5MB limit
});
// 3. Single File Route
app.post('/profile-pic', upload.single('avatar'), (req, res) => {
try {
res.status(200).json({
message: 'Upload successful',
file: req.file
});
} catch (error) {
res.status(400).send('Error uploading file.');
}
});
// 4. Multiple Files Route
app.post('/documents', upload.array('docs', 3), (req, res) => {
res.send(`Received ${req.files.length} documents.`);
});
// 5. Serve Files
app.use('/uploads', express.static('uploads'));
app.listen(3000, () => {
console.log('Server started on http://localhost:3000');
});
Summary
Express.js, paired with multer, provides a robust and highly configurable ecosystem for handling file uploads. By defining a storage engine, you control where and how files are saved. By implementing fileFilter and limits, you ensure your application remains secure and efficient. Remember to always sanitize filenames and validate file types to build a safe user experience.