File Uploads
Overview
Standard JSON POST requests cannot efficiently handle binary file uploads (like user avatars). Instead, browsers use a specialized protocol called multipart/form-data. This stream breaks the payload into 'parts' (e.g., Part 1 is the username string, Part 2 is the raw binary image stream). Express express.json() completely ignores multipart data. To intercept, parse, and safely save physical files to the server, you must use a specialized streaming middleware. Multer is the industry standard for this in the Express ecosystem.
Syntax
// npm install multer
const express = require('express');
const multer = require('multer');
const app = express();
// 1. Configure where Multer should save the files, and how to name them
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/'); // Save inside the 'uploads' folder
},
filename: (req, file, cb) => {
// Securely rename the file to avoid naming collisions!
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, uniqueSuffix + '-' + file.originalname);
}
});
// 2. Initialize the middleware with strict size limits (e.g., 5MB max)
const upload = multer({
storage: storage,
limits: { fileSize: 5 * 1024 * 1024 }
});
// 3. Inject it into the specific route pipeline
// 'avatar' MUST perfectly match the name attribute in the HTML form!
app.post('/api/upload', upload.single('avatar'), (req, res) => {
// Multer intercepted the stream, saved the file, and attached metadata here!
console.log(req.file.path);
// It also perfectly parses the rest of the text fields!
console.log(req.body.username);
res.send("File uploaded securely!");
});Common Pitfalls
- Trusting the
file.originalnameorfile.mimetype. If a hacker uploads a malicious executable script but names itcute_cat.jpg, Multer will blindly trust the.jpgextension and save it. If the server later executes that file, you are compromised. You MUST use a binary-inspection library (likefile-type) to physically read the first few bytes (Magic Numbers) of the file to prove it is mathematically a real image. - Saving files locally on server RAM/Disk in production. If you host on Heroku or AWS Elastic Beanstalk, the local hard drive is 'ephemeral' (it gets wiped clean every time the server restarts). The industry standard is to use Multer to stream the file directly up to cloud storage (like an AWS S3 Bucket) instead of saving it locally.
Interview Questions
multipart/form-data encoding type for file uploads instead of standard application/json?JSON is strictly a text-based protocol. To send a binary image in JSON, you must encode it to a Base64 string, which inherently inflates the file size by 33%, wasting massive amounts of bandwidth. Multipart streams allow the browser to transmit the pure, raw binary bytes directly over the TCP socket.
Real-World Example
Using Multer's File Filter to strictly reject any upload that isn't a PNG or JPEG before it even touches the hard drive.
const fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true); // Accept the file
} else {
cb(new Error('Invalid file type. Only JPG and PNG are allowed.'), false); // Reject!
}
};
const upload = multer({ storage, fileFilter });Check Your Knowledge
Test your understanding of File Uploads with these quick questions.