How to handle file uploads in Express.js with Multer?
File Uploads in Express.js
Express.js doesn't handle file uploads natively. Multer is the most popular middleware for handling multipart/form-data (file uploads).
Setup
bash
npm install multerBasic File Upload
js
const multer = require('multer');
// Store in memory (for processing/uploading to cloud)
const upload = multer({ storage: multer.memoryStorage() });
// Single file upload
app.post('/upload/avatar', upload.single('avatar'), (req, res) => {
console.log(req.file);
// {
// fieldname: 'avatar',
// originalname: 'photo.jpg',
// mimetype: 'image/jpeg',
// size: 123456,
// buffer: <Buffer ...>
// }
res.json({ message: 'Uploaded!', file: req.file.originalname });
});Disk Storage with Custom Naming
js
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
const ext = path.extname(file.originalname);
cb(null, file.fieldname + '-' + uniqueSuffix + ext);
}
});
const upload = multer({ storage });
app.post('/upload', upload.single('file'), (req, res) => {
res.json({ path: req.file.path });
});Multiple Files
js
// Multiple files with same field name
app.post('/upload/photos', upload.array('photos', 10), (req, res) => {
console.log(req.files); // Array of file objects
res.json({ count: req.files.length });
});
// Multiple fields
const cpUpload = upload.fields([
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]);
app.post('/upload/profile', cpUpload, (req, res) => {
console.log(req.files['avatar']); // Array with 1 file
console.log(req.files['gallery']); // Array with up to 8 files
});File Validation
js
const upload = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // 5MB max
files: 5 // Max 5 files
},
fileFilter: (req, file, cb) => {
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('Only JPEG, PNG, and WebP images are allowed'), false);
}
}
});
// Handle Multer errors
app.post('/upload', upload.single('image'), (req, res) => {
res.json({ success: true });
});
app.use((err, req, res, next) => {
if (err instanceof multer.MulterError) {
if (err.code === 'LIMIT_FILE_SIZE') {
return res.status(400).json({ error: 'File too large (max 5MB)' });
}
return res.status(400).json({ error: err.message });
}
next(err);
});Upload to Cloud (S3 Example)
js
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const upload = multer({ storage: multer.memoryStorage() });
const s3 = new S3Client({ region: 'us-east-1' });
app.post('/upload', upload.single('file'), async (req, res) => {
const key = `uploads/${Date.now()}-${req.file.originalname}`;
await s3.send(new PutObjectCommand({
Bucket: process.env.S3_BUCKET,
Key: key,
Body: req.file.buffer,
ContentType: req.file.mimetype
}));
res.json({ url: `https://${process.env.S3_BUCKET}.s3.amazonaws.com/${key}` });
});Summary
| Feature | Implementation |
|---|---|
| Single file | upload.single('field') |
| Multiple files | upload.array('field', max) |
| Multiple fields | upload.fields([...]) |
| File size limit | limits: { fileSize: ... } |
| Type validation | fileFilter callback |
| Memory storage | multer.memoryStorage() |
| Disk storage | multer.diskStorage({...}) |
Production tip: Always validate file type and size. Store files in cloud storage (S3, GCS, Azure Blob) rather than on disk. Use signed URLs for secure access. Process images asynchronously (resize, compress) using libraries like
sharp.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.