Multer is Express middleware that parses
multipart/form‑data
— the encoding used for file uploads.
It adds a file
/ files
object to the
req
object, containing metadata and (optionally) the file
buffer or path.
single()
,
array()
,
fields()
,
none()
,
any()
.
// terminal
npm i multer
// app.js
import express from "express";
import multer from "multer";
const upload = multer({ dest: "uploads/" });
const app = express();
app.post("/profile",
upload.single("avatar"), // field name: avatar
(req, res) => {
console.log(req.file); // metadata + file.path
res.json({ status: "ok" });
}
);
app.listen(3000);
Note: The temporary uploads/
directory
must exist or Multer throws ENOENT
.
diskStorage()
const storage = multer.diskStorage({
destination(req, file, cb){
cb(null, "public/img");
},
filename(req, file, cb){
const unique = Date.now() + "-" + Math.round(Math.random()*1e9);
cb(null, unique + "-" + file.originalname);
}
});
const upload = multer({ storage });
memoryStorage()
Stores files in RAM — ideal for quick transformations (e.g., Sharp image resize) before streaming elsewhere.
const upload = multer({ storage: multer.memoryStorage() });
Implement a class exposing
_handleFile()
and
_removeFile()
to stream to S3,
GridFS or any destination.
upload.single("avatar")
upload.array("photos", 5);
upload.fields([
{ name:"avatar", maxCount:1 },
{ name:"gallery", maxCount:8 }
]);
upload.any();
upload.none(); // only text fields
function imageFilter(req, file, cb){
const ok = ["image/png", "image/jpeg"].includes(file.mimetype);
ok ? cb(null, true) : cb(new Error("Only PNG/JPEG allowed"));
}
const upload = multer({ storage, fileFilter: imageFilter });
Common limits:
const upload = multer({
storage,
limits:{
fileSize: 2 * 1024 * 1024, // 2 MB
files: 5,
parts: 20,
}
});
Security checklist:
public/
.clamd
or AWS AV).
app.post("/upload", (req, res, next) => {
upload.single("doc")(req, res, function(err){
if (err instanceof multer.MulterError){
// Multer‑specific (LIMIT_FILE_SIZE, LIMIT_PART_COUNT…)
return res.status(400).json({ error: err.code });
} else if (err){
return next(err); // unknown
}
res.send("Uploaded ✓");
});
});
For large files (> 50 MB) or serverless environments, prefer streaming directly to cloud storage to avoid local disk I/O:
// example: multer‑s3
import multerS3 from "multer-s3";
import { S3Client } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
const upload = multer({
storage: multerS3({
s3,
bucket: "my‑bucket",
key: (req, file, cb) => cb(null, Date.now() + "-" + file.originalname)
})
});
multipart/form‑data
.req.body
may be empty if you place other
body‑parsing middleware before Multer.array()
; each
file lands in req.files
(array).await
downstream cloud SDK uploads when
using memoryStorage()
.Method | Signature | Purpose |
---|---|---|
single(name) |
string → middleware | Handle exactly one file on a field. |
array(name,max) |
string, int → middleware | Handle <= max files under one field. |
fields(spec[]) |
FieldSpec[] → middleware | Mixed named fields. |
none() |
→ middleware | Reject any file upload. |
any() |
→ middleware | Accept files on any field. |