Node.js File Uploads
File uploads let visitors send photos, documents, and other files to your server. Profile pictures and resume forms use this feature. Express handles uploads with a popular library called Multer.
How an Upload Works
A normal form sends short text. A file is large and binary, so the browser packs it in a special format called multipart form data. Multer unpacks that format and saves the file.
+---------+ multipart data +--------+ saves +-----------+
| Browser | ---------------> | Multer | -------> | uploads/ |
+---------+ +--------+ +-----------+
|
v
req.file (file details)
req.body (text fields)
Install Multer
npm install express multerBuild the Upload Form
The form needs the enctype attribute. Without it, the file never leaves the browser.
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="text" name="title">
<input type="file" name="photo">
<button type="submit">Upload</button>
</form>Save One File
const express = require("express");
const multer = require("multer");
const app = express();
const upload = multer({ dest: "uploads/" });
app.post("/upload", upload.single("photo"), (req, res) => {
console.log(req.file);
console.log(req.body.title);
res.send("File saved.");
});
app.listen(3000);The text photo inside upload.single matches the input name in the form.
What req.file Contains
- originalname holds the name on the visitor's computer.
- filename holds the saved name.
- mimetype holds the file type, such as image/png.
- size holds the file size in bytes.
- path holds the saved location.
Control File Names and Folders
The simple option saves files with random names and no extension. Use diskStorage for full control.
const path = require("path");
const storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, "uploads/"),
filename: (req, file, cb) => {
const unique = Date.now() + "-" + Math.round(Math.random() * 1e9);
cb(null, unique + path.extname(file.originalname));
}
});
const upload = multer({ storage });A unique name stops one visitor from overwriting another visitor's file.
Upload Many Files
// Many files from one input
app.post("/gallery", upload.array("photos", 5), (req, res) => {
res.send(req.files.length + " files saved.");
});
// Files from different inputs
const fields = upload.fields([
{ name: "avatar", maxCount: 1 },
{ name: "documents", maxCount: 3 }
]);
upload.single("photo") --> req.file (one file)
upload.array("photos", 5) --> req.files (list of files)
upload.fields([...]) --> req.files (grouped by input name)
Set Limits
Limits protect your server from huge files.
const upload = multer({
storage,
limits: { fileSize: 2 * 1024 * 1024 } // 2 MB
});Filter File Types
A filter accepts or rejects each file before saving.
const allowed = ["image/jpeg", "image/png", "image/webp"];
const upload = multer({
storage,
limits: { fileSize: 2 * 1024 * 1024 },
fileFilter: (req, file, cb) => {
if (allowed.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error("Only JPG, PNG, or WEBP images are allowed."));
}
}
});Handle Upload Errors
app.use((err, req, res, next) => {
if (err instanceof multer.MulterError) {
return res.status(400).send("Upload problem: " + err.message);
}
if (err) {
return res.status(400).send(err.message);
}
next();
});Place this handler below all routes.
Show Uploaded Files
Serve the upload folder as static files to display images.
app.use("/files", express.static("uploads"));A saved file named 171-photo.png opens at /files/171-photo.png.
Safety Rules
- Limit file size and file type every time.
- Rename files and ignore the visitor's file name.
- Store uploads outside the code folder.
- Never run uploaded files as programs.
- Scan documents for harmful content when your app allows public uploads.
- Consider cloud storage for large projects.
Practice Tasks
- Build a profile picture form that accepts one image up to 1 MB.
- Rename each saved file with a timestamp.
- Reject a PDF file and show a friendly message.
