Multer File Upload in Express.js – Complete Guide
Learn Multer file upload implementation in Express.js. Complete guide with single/multiple files, file validation, error handling, and middleware configuration. Step-by-step tutorial.
Multer is the most popular and reliable middleware for handling file uploads in Node.js and Express.js applications. File uploads are one of those features that seem simple until you actually try to implement them securely. I've dealt with everything from users uploading 500MB files that crash the server to malicious files that could compromise the system. When I first started working with file uploads in Express.js, I quickly learned that handling multipart/form-data isn't as straightforward as it appears.
That's where Multer comes in. Multer is a middleware specifically designed for handling file uploads in Express.js and Node.js applications. Express multer and node multer process multipart/form-data, which is what browsers send when you submit a form with file inputs. Without multer, you'd have to manually parse the multipart data, which is complex and error-prone. Multer makes file uploads simple and secure.
In this complete multer guide, I'll walk you through implementing file uploads the way I do it in production applications using express multer and node multer. We'll cover single file uploads (like product images), multiple file uploads (like product galleries), file validation (to prevent malicious uploads), size limits (to prevent server overload), and proper error handling. I'll also share some security best practices I've learned the hard way when working with multer.
Table of Contents: Multer Guide
How to Install Multer: Express Multer & Node Multer Setup
Installing multer is straightforward. Whether you're using express multer or node multer, the installation process is the same. Here's how to install multer in your Node.js or Express.js project:
npm install multerMulter Configuration: Express Multer & Node Multer Setup Guide
Setting up multer with disk storage is the most common configuration for express multer and node multer applications. Here's how to configure multer:
const multer = require("multer");
const path = require("path");
const fs = require("fs");
// Create uploads directory if it doesn't exist
const uploadDir = "uploads/";
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, uploadDir);
},
filename: function (req, file, cb) {
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 10000);
const uploadedFileName =
file.fieldname + "-" + uniqueSuffix + "." + file.mimetype.split("/")[1];
cb(null, uploadedFileName);
},
});
const upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB limit
},
fileFilter: (req, file, cb) => {
// Only allow images
if (file.mimetype.startsWith("image/")) {
cb(null, true);
} else {
cb(new Error("Only image files are allowed!"), false);
}
},
});Single File Upload with Multer
const uploadSingleFile = upload.single("file");
function storeSingleFile(req, res, next) {
return new Promise((resolve, reject) => {
uploadSingleFile(req, res, async function (err) {
if (err instanceof multer.MulterError) {
console.log("Multer error:", err);
reject(err);
} else if (err) {
console.log("Upload error:", err);
reject(err);
}
resolve({
message: "File uploaded successfully",
body: req.body,
file: req.file ? req.file : null,
});
});
});
}
// Usage in route
router.post("/upload", async (req, res, next) => {
try {
await storeSingleFile(req, res, next);
res.json({
success: true,
message: "File uploaded",
file: req.file,
});
} catch (error) {
res.status(400).json({
success: false,
message: error.message,
});
}
});Multiple File Upload with Multer
Handling product images with main image and gallery:
// For products: main image (required) + gallery images (optional)
const uploadProductFiles = upload.fields([
{ name: "product_image", maxCount: 1 }, // Main product image (required)
{ name: "product_gallery", maxCount: 10 }, // Gallery images (optional, max 10)
]);
function storeProductFiles(req, res, next) {
return new Promise((resolve, reject) => {
uploadProductFiles(req, res, async function (err) {
if (err instanceof multer.MulterError) {
console.log("Multer error for product files:", err);
reject(err);
} else if (err) {
console.log("Upload error for product files:", err);
reject(err);
}
resolve({
message: "Files uploaded successfully",
body: req.body,
files: req.files ? req.files : null,
});
});
});
}
// Usage in route
router.post("/products", async (req, res, next) => {
try {
await storeProductFiles(req, res, next);
// Access files
const mainImage = req.files?.product_image?.[0];
const galleryImages = req.files?.product_gallery || [];
// Process files...
res.json({
success: true,
message: "Product created",
files: {
mainImage: mainImage?.filename,
gallery: galleryImages.map(f => f.filename),
},
});
} catch (error) {
res.status(400).json({
success: false,
message: error.message,
});
}
});File Validation
Adding custom validation:
const upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB
files: 10, // Max 10 files
},
fileFilter: (req, file, cb) => {
// Check file type
const allowedTypes = ["image/jpeg", "image/jpg", "image/png", "image/webp"];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error("Invalid file type. Only JPEG, PNG, and WebP are allowed!"), false);
}
},
});Error Handling
router.post("/upload", async (req, res) => {
try {
await storeProductFiles(req, res);
// Check if main image is required
if (!req.files?.product_image || req.files.product_image.length === 0) {
return res.status(400).json({
success: false,
message: "Product image is required",
});
}
// Process files...
} catch (error) {
if (error instanceof multer.MulterError) {
if (error.code === "LIMIT_FILE_SIZE") {
return res.status(400).json({
success: false,
message: "File size too large. Maximum size is 5MB",
});
}
if (error.code === "LIMIT_FILE_COUNT") {
return res.status(400).json({
success: false,
message: "Too many files. Maximum is 10 files",
});
}
}
return res.status(400).json({
success: false,
message: error.message || "File upload failed",
});
}
});What is Multer? Express Multer and Node Multer Explained
What is multer? Multer is a Node.js middleware for handling multipart/form-data, which is primarily used for uploading files. Multer is the most popular solution for handling file uploads in Node.js and Express.js applications. When you ask "what is multer in express?", express multer is the integration of multer with Express.js.
What is express multer? Express multer is the integration of multer middleware with Express.js. Express multer processes the multipart/form-data that browsers send when submitting forms with file inputs. Without express multer, you'd need to manually parse multipart data, which is complex and error-prone. Express multer makes file uploads in Express.js simple and secure.
What is node multer? Node multer refers to using multer in Node.js applications. Multer works with any Node.js framework, not just Express.js. Whether you're using express multer or node multer, the core multer functionality remains the same.
What is express multer file? When you upload a file using express multer or node multer, the uploaded file object (express.multer.file) contains properties like fieldname, originalname, mimetype, size, destination, filename, and path.
Multer TypeScript: Express Multer and Node Multer Type Setup
When working with multer typescript, express multer typescript, or node multer typescript, you need to properly type the multer file object. Here's how to set up multer with TypeScript:
import multer from "multer";
import { Request } from "express";
// Express multer file typescript type
interface MulterRequest extends Request {
file?: Express.Multer.File;
files?: {
[fieldname: string]: Express.Multer.File[];
} | Express.Multer.File[];
}
// TypeScript type for express.multer.file
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "uploads/");
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 10000);
cb(null, `${file.fieldname}-${uniqueSuffix}${getFileExtension(file.originalname)}`);
},
});
// Helper function to get file extension
function getFileExtension(filename: string): string {
return filename.substring(filename.lastIndexOf("."));
}
const upload = multer({
storage: storage,
limits: { fileSize: 5 * 1024 * 1024 },
});
// Express multer file typescript usage
router.post("/upload", upload.single("file"), (req: MulterRequest, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
// Access express multer file properties
const file: Express.Multer.File = req.file;
console.log("Express multer file type:", file.mimetype);
console.log("Express multer file size:", file.size);
console.log("Express multer file originalname:", file.originalname);
res.json({
message: "File uploaded",
file: {
filename: file.filename,
originalname: file.originalname,
mimetype: file.mimetype,
size: file.size,
},
});
});Express multer file typescript typing ensures type safety when accessing file properties. The Express.Multer.File type includes all express multer file properties like fieldname, originalname,encoding, mimetype,size, destination,filename, and path.
Multer File Buffer: Express Multer and Node Multer Memory Storage
When using multer memoryStorage with express multer or node multer, files are stored in memory as Buffer objects instead of being saved to disk. This is useful when you need to process files (like uploading to cloud storage) without saving them locally. Here's how to handle multer file buffer with express multer and node multer:
const multer = require("multer");
// Express multer memoryStorage - files stored as buffer
const storage = multer.memoryStorage();
const upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB
},
});
// Express multer file buffer example
router.post("/upload", upload.single("file"), async (req, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
// Express multer file buffer is available in req.file.buffer
const fileBuffer = req.file.buffer;
// Check if express multer file buffer undefined
if (!fileBuffer) {
return res.status(400).json({ error: "File buffer is undefined" });
}
// Process the buffer (e.g., upload to cloud storage)
console.log("Express multer file buffer size:", fileBuffer.length);
console.log("Express multer file mimetype:", req.file.mimetype);
// Example: Convert express multer file buffer to base64
const base64String = fileBuffer.toString("base64");
res.json({
message: "File processed",
bufferSize: fileBuffer.length,
mimetype: req.file.mimetype,
base64: base64String.substring(0, 100) + "...", // First 100 chars
});
});Express multer file buffer undefined can occur if the file wasn't uploaded correctly or if you're using diskStorage instead of memoryStorage. With memoryStorage, the express multer file buffer contains the file data as a Buffer object, which you can process directly without saving to disk.
Express Multer File to Base64 and Blob
Converting express multer file to base64 or express multer file to blob is common when you need to send file data to APIs or store it in databases. Here are examples:
const multer = require("multer");
const fs = require("fs");
const upload = multer({ storage: multer.memoryStorage() });
// Convert express multer file to base64
router.post("/upload-base64", upload.single("file"), (req, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
// Express multer file to base64
const base64String = req.file.buffer.toString("base64");
const base64DataUri = `data:${req.file.mimetype};base64,${base64String}`;
res.json({
message: "File converted to base64",
base64: base64DataUri,
mimetype: req.file.mimetype,
});
});
// Convert express multer file to blob (for browser)
router.post("/upload-blob", upload.single("file"), (req, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
// Express multer file to blob - send buffer as blob response
res.setHeader("Content-Type", req.file.mimetype);
res.setHeader("Content-Disposition", `attachment; filename="${req.file.originalname}"`);
res.send(req.file.buffer);
});
// Convert buffer to express multer file (reverse operation)
function createExpressMulterFileFromBuffer(buffer, originalname, mimetype) {
return {
fieldname: "file",
originalname: originalname,
encoding: "7bit",
mimetype: mimetype,
buffer: buffer,
size: buffer.length,
};
}
// Base64 to express multer file
router.post("/base64-to-file", (req, res) => {
const { base64, filename, mimetype } = req.body;
// Base64 to express multer file
const buffer = Buffer.from(base64, "base64");
const file = createExpressMulterFileFromBuffer(buffer, filename, mimetype);
// Now you can process the file as if it came from multer
res.json({
message: "Base64 converted to file",
fileSize: file.size,
mimetype: file.mimetype,
});
});Express Multer File Properties
Understanding express multer file properties is essential for working with uploaded files. Here's a complete reference of all express multer file properties:
router.post("/upload", upload.single("file"), (req, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
const file = req.file;
// Express multer file properties
const fileProperties = {
// Basic properties
fieldname: file.fieldname, // Name of the form field
originalname: file.originalname, // Original filename
encoding: file.encoding, // File encoding (usually "7bit")
mimetype: file.mimetype, // MIME type (e.g., "image/jpeg")
size: file.size, // File size in bytes
// Storage properties (for diskStorage)
destination: file.destination, // Directory where file is stored
filename: file.filename, // Generated filename
path: file.path, // Full path to file
// Buffer property (for memoryStorage)
buffer: file.buffer, // File buffer (if using memoryStorage)
};
// Express multer file get extension
function getFileExtension(filename) {
return filename.substring(filename.lastIndexOf("."));
}
// Express multer file extension
const extension = getFileExtension(file.originalname);
// Express multer file originalname
const originalName = file.originalname;
// Express multer file mimetype
const mimeType = file.mimetype;
// Express multer file type (derived from mimetype)
const fileType = mimeType.split("/")[0]; // "image", "video", etc.
res.json({
message: "File properties",
properties: fileProperties,
extension: extension,
fileType: fileType,
});
});Multer with Cloudinary and S3: Express Multer and Node Multer Cloud Storage
Using express multer cloudinary or express multer s3 allows you to upload files directly to cloud storage. Here's how to implement both:
const multer = require("multer");
const cloudinary = require("cloudinary").v2;
const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3");
// Express multer cloudinary example
const uploadToCloudinary = multer({ storage: multer.memoryStorage() });
router.post("/upload-cloudinary", uploadToCloudinary.single("file"), async (req, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
try {
// Upload express multer file buffer to Cloudinary
const result = await new Promise((resolve, reject) => {
const uploadStream = cloudinary.uploader.upload_stream(
{ folder: "uploads" },
(error, result) => {
if (error) reject(error);
else resolve(result);
}
);
uploadStream.end(req.file.buffer);
});
res.json({
message: "File uploaded to Cloudinary",
url: result.secure_url,
publicId: result.public_id,
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Express multer s3 example
const uploadToS3 = multer({ storage: multer.memoryStorage() });
const s3Client = new S3Client({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
});
router.post("/upload-s3", uploadToS3.single("file"), async (req, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
try {
const key = `uploads/${Date.now()}-${req.file.originalname}`;
// Upload express multer file buffer to S3
const command = new PutObjectCommand({
Bucket: process.env.S3_BUCKET_NAME,
Key: key,
Body: req.file.buffer,
ContentType: req.file.mimetype,
});
await s3Client.send(command);
const fileUrl = `https://${process.env.S3_BUCKET_NAME}.s3.${process.env.AWS_REGION}.amazonaws.com/${key}`;
res.json({
message: "File uploaded to S3",
url: fileUrl,
key: key,
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});Multer vs express-fileupload: Which Should You Choose?
When choosing between multer (including express multer and node multer) and express-fileupload, here are the key differences. Multer is generally the preferred choice for most applications:
| Feature | Express Multer | express-fileupload |
|---|---|---|
| Popularity | More popular, widely used | Less popular |
| Storage Options | diskStorage, memoryStorage, custom | Memory only, manual disk save |
| TypeScript Support | Excellent (express multer typescript) | Limited |
| File Validation | Built-in fileFilter | Manual validation |
| Error Handling | MulterError with specific codes | Generic errors |
| Maintenance | Active maintenance | Less active |
Multer alternative considerations: While express-fileupload is an alternative to multer, multer (including express multer and node multer) is generally preferred for production applications due to better TypeScript support, more storage options, and active maintenance. The express-fileupload vs multer debate usually favors multer for enterprise applications. Multer is the industry standard for file uploads in Node.js.
Common Multer Errors and Solutions: Express Multer and Node Multer
Here are common express multer error handling scenarios and their solutions:
1. Express.multer.file Error
express.multer.file error often occurs when TypeScript can't find the type definition.
// Solution: Install types
npm install --save-dev @types/multer
// Then import properly
import multer from "multer";
import { Request } from "express";
interface MulterRequest extends Request {
file?: Express.Multer.File;
}2. Express Multer File Not Found
express multer file not found happens when req.file is undefined. Always check if file exists.
router.post("/upload", upload.single("file"), (req, res) => {
// Check if express multer file not found
if (!req.file) {
return res.status(400).json({
error: "No file uploaded. Make sure form field name is 'file'"
});
}
// Process file...
});3. Express Multer Unexpected End of Form
express multer unexpected end of form usually means the request was interrupted or the file is too large.
// Solution: Increase body parser limits
const express = require("express");
const app = express();
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
// Also set multer limits
const upload = multer({
storage: storage,
limits: {
fileSize: 10 * 1024 * 1024, // 10MB
},
});4. Express Has No Exported Member Multer
express has no exported member multer is a TypeScript error. Multer is not part of Express.
// Wrong
import { multer } from "express";
// Correct
import multer from "multer";
// Or for CommonJS
const multer = require("multer");5. Cannot Find Namespace Express Multer
cannot find namespace express multer means TypeScript types aren't installed.
// Install types
npm install --save-dev @types/multer @types/express
// Then use
import { Request } from "express";
import multer from "multer";
// Express.Multer.File is now available
const file: Express.Multer.File = req.file;6. Express Multer File Encoding Deprecated
express multer file encoding deprecated warning appears but doesn't affect functionality. The encoding property is still available but may be removed in future versions.
// The encoding property is deprecated but still works
// Use mimetype instead for file type information
const fileType = req.file.mimetype; // "image/jpeg"
// Instead of: req.file.encoding (deprecated)Multer with NestJS: Express Multer Integration
Using express multer nestjs or nestjs express multer requires the@nestjs/platform-express package. Here's how to implementnestjs express multer file uploads:
// Install: npm install @nestjs/platform-express multer
// Install types: npm install --save-dev @types/multer
import { Controller, Post, UseInterceptors, UploadedFile, UploadedFiles } from "@nestjs/common";
import { FileInterceptor, FilesInterceptor } from "@nestjs/platform-express";
import { Express } from "express";
@Controller("upload")
export class UploadController {
// NestJS express multer file - single file
@Post("single")
@UseInterceptors(
FileInterceptor("file", {
storage: multer.diskStorage({
destination: "./uploads",
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 10000);
cb(null, `${file.fieldname}-${uniqueSuffix}${getExtension(file.originalname)}`);
},
}),
limits: { fileSize: 5 * 1024 * 1024 },
})
)
uploadFile(@UploadedFile() file: Express.Multer.File) {
// NestJS express.multer.file type
return {
message: "File uploaded",
filename: file.filename,
originalname: file.originalname,
};
}
// NestJS express multer file - multiple files
@Post("multiple")
@UseInterceptors(
FilesInterceptor("files", 10, {
storage: multer.memoryStorage(),
})
)
uploadFiles(@UploadedFiles() files: Express.Multer.File[]) {
return {
message: "Files uploaded",
count: files.length,
files: files.map(f => ({
originalname: f.originalname,
size: f.size,
})),
};
}
}
// For nestjs platform express multer vulnerability, always:
// 1. Validate file types
// 2. Set file size limits
// 3. Sanitize filenames
// 4. Use latest versions: npm install nestjs platform express multerMulter Best Practices: Express Multer and Node Multer Production Tips
Following multer best practices ensures secure and efficient file uploads. Whether you're using express multer or node multer, these multer best practices apply. Here's a comprehensive production-ready example:
const multer = require("multer");
const path = require("path");
const fs = require("fs");
// Best Practice 1: Create uploads directory if it doesn't exist
const uploadDir = "uploads/";
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
// Best Practice 2: Validate file types strictly
const allowedMimeTypes = [
"image/jpeg",
"image/jpg",
"image/png",
"image/webp",
"image/gif",
];
// Best Practice 3: Sanitize filenames
function sanitizeFilename(filename) {
return filename
.replace(/[^a-zA-Z0-9.-]/g, "_")
.replace(/s+/g, "_")
.substring(0, 255);
}
// Best Practice 4: Use diskStorage with proper configuration
const storage = multer.diskStorage({
destination: function (req, file, cb) {
// Organize files by date
const dateFolder = new Date().toISOString().split("T")[0];
const folderPath = path.join(uploadDir, dateFolder);
if (!fs.existsSync(folderPath)) {
fs.mkdirSync(folderPath, { recursive: true });
}
cb(null, folderPath);
},
filename: function (req, file, cb) {
// Best Practice 5: Use unique filenames
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 10000);
const sanitized = sanitizeFilename(file.originalname);
const ext = path.extname(sanitized);
const name = path.basename(sanitized, ext);
cb(null, `${name}-${uniqueSuffix}${ext}`);
},
});
// Best Practice 6: Set appropriate file size limits
const upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB
files: 10, // Max 10 files
fields: 10, // Max 10 non-file fields
},
fileFilter: (req, file, cb) => {
// Best Practice 7: Validate file types
if (allowedMimeTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error(`Invalid file type. Allowed types: ${allowedMimeTypes.join(", ")}`), false);
}
},
});
// Best Practice 8: Handle errors gracefully
router.post("/upload", upload.single("file"), (req, res) => {
try {
if (!req.file) {
return res.status(400).json({
success: false,
message: "No file uploaded",
});
}
// Best Practice 9: Log file information
console.log("File uploaded:", {
originalname: req.file.originalname,
filename: req.file.filename,
size: req.file.size,
mimetype: req.file.mimetype,
});
res.json({
success: true,
message: "File uploaded successfully",
file: {
filename: req.file.filename,
path: req.file.path,
size: req.file.size,
mimetype: req.file.mimetype,
},
});
} catch (error) {
// Best Practice 10: Proper error handling
console.error("Upload error:", error);
res.status(500).json({
success: false,
message: "File upload failed",
error: error.message,
});
}
});
// Best Practice 11: Clean up old files periodically (use cron job)
function cleanupOldFiles(daysOld = 30) {
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - daysOld);
// Implementation for cleaning old files...
}
// Best Practice 12: Use cloud storage for production
// Consider using express multer cloudinary or express multer s3 for productionSecurity Best Practices
- Always validate file types - Don't trust client-provided MIME types
- Set file size limits - Prevent DoS attacks from large files
- Sanitize filenames - Prevent path traversal attacks
- Scan files for viruses - Use antivirus scanning in production
- Use HTTPS - Encrypt file uploads in transit
- Implement rate limiting - Prevent abuse
- Store files outside web root - Prevent direct access
- Use cloud storage - Offload storage to CDN/cloud services
Express Multer File Extension and Type Handling
Getting the express multer file extension and handling express multer file typeis essential for proper file processing. Here are practical examples:
const path = require("path");
const mime = require("mime-types");
// Express multer file get extension
function getFileExtension(filename) {
return path.extname(filename).toLowerCase();
}
// Express multer file extension from originalname
router.post("/upload", upload.single("file"), (req, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
// Express multer file extension
const extension = getFileExtension(req.file.originalname);
// Express multer file type (from mimetype)
const fileType = req.file.mimetype.split("/")[0]; // "image", "video", "application"
const mimeSubtype = req.file.mimetype.split("/")[1]; // "jpeg", "png", "pdf"
// Express multer file mimetype
const mimetype = req.file.mimetype;
// Validate extension matches mimetype
const expectedExtension = mime.extension(mimetype);
const isValid = extension === `.${expectedExtension}`;
res.json({
extension: extension,
fileType: fileType,
mimetype: mimetype,
mimeSubtype: mimeSubtype,
isValidExtension: isValid,
originalname: req.file.originalname,
});
});
// Express multer file type validation
function validateFileType(file, allowedTypes = ["image"]) {
const fileType = file.mimetype.split("/")[0];
return allowedTypes.includes(fileType);
}
// Usage
router.post("/upload-image", upload.single("file"), (req, res) => {
if (!req.file) {
return res.status(400).json({ error: "No file uploaded" });
}
if (!validateFileType(req.file, ["image"])) {
return res.status(400).json({ error: "Only images are allowed" });
}
res.json({ message: "Image uploaded successfully" });
});Testing Express Multer with Jest
Testing file uploads requires mock express multer file or jest mock express multer file. Here's how to test express multer endpoints:
// jest.config.js or setup
// Mock express multer file for testing
// Create mock express multer file
function createMockExpressMulterFile(overrides = {}) {
return {
fieldname: "file",
originalname: "test-image.jpg",
encoding: "7bit",
mimetype: "image/jpeg",
size: 1024,
destination: "uploads/",
filename: "test-image-1234567890.jpg",
path: "uploads/test-image-1234567890.jpg",
buffer: Buffer.from("fake image data"),
...overrides,
};
}
// Jest mock express multer file example
describe("File Upload", () => {
it("should upload file successfully", async () => {
const mockFile = createMockExpressMulterFile({
originalname: "test.jpg",
mimetype: "image/jpeg",
size: 2048,
});
const req = {
file: mockFile,
body: {},
};
const res = {
json: jest.fn(),
status: jest.fn().mockReturnThis(),
};
// Your upload handler
await uploadHandler(req, res);
expect(res.json).toHaveBeenCalledWith(
expect.objectContaining({
success: true,
file: expect.objectContaining({
filename: expect.any(String),
}),
})
);
});
it("should handle express multer file not found", async () => {
const req = {
file: undefined,
body: {},
};
const res = {
json: jest.fn(),
status: jest.fn().mockReturnThis(),
};
await uploadHandler(req, res);
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith(
expect.objectContaining({
error: expect.any(String),
})
);
});
});
// Mock multer middleware for integration tests
jest.mock("multer", () => {
return jest.fn(() => ({
single: () => (req, res, next) => {
req.file = createMockExpressMulterFile();
next();
},
array: () => (req, res, next) => {
req.files = [createMockExpressMulterFile()];
next();
},
fields: () => (req, res, next) => {
req.files = {
field1: [createMockExpressMulterFile()],
};
next();
},
}));
});Conclusion: Why Multer is the Best Choice for File Uploads
Multer provides a robust and flexible solution for handling file uploads in Node.js and Express.js applications. Throughout this complete multer guide, we've covered everything from basic multer file upload to advanced topics like multer typescript, multer file buffer handling, and multer cloudinary integration. Whether you're using express multer or node multer, multer is the industry standard for file uploads.
Key takeaways for implementing multer in production:
- Always use multer middleware (whether express multer or node multer) with proper validation and error handling
- Implement multer file size limit to prevent DoS attacks
- Use multer memoryStorage when processing files before uploading to cloud storage
- Leverage multer typescript for type safety in TypeScript projects
- Handle common errors like multer file not found and multer unexpected end of form
- Consider multer cloudinary or multer s3 for production deployments
- Follow multer best practices for security and performance
Whether you're building a simple file upload feature or a complex system with multer multiple files, multer nestjs integration, or multer file to base64 conversions, this multer guide provides the foundation you need. Remember to always validate file types, sanitize filenames, and implement proper error handling for a secure and reliable file upload system. Multer makes file uploads simple, secure, and efficient.
For more information, check out the multer documentation and multer github repository for the latest updates and examples. The multer example code provided in this guide can be adapted to fit your specific use case. Multer is the solution you've been looking for for file uploads in Node.js and Express.js.
Related Articles
Cloudinary Image Upload in Node.js: Complete Guide with Examples
Implement Cloudinary image upload with optimization, transformations, and CDN delivery.
Express.js REST API Setup: Complete Guide with Error Handling
Learn how to set up a production-ready Express.js REST API with CORS and error handling.
JWT Authentication in Express.js and Node.js: Complete Guide
Learn how to implement JWT authentication with bcrypt password hashing and protected routes.
Sequelize ORM with MySQL Setup: Complete Guide for Node.js
Complete guide with connection pooling, migrations, and best practices for database setup.