Back to Blog
Node.js13 min read

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 multer

Multer 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:

FeatureExpress Multerexpress-fileupload
PopularityMore popular, widely usedLess popular
Storage OptionsdiskStorage, memoryStorage, customMemory only, manual disk save
TypeScript SupportExcellent (express multer typescript)Limited
File ValidationBuilt-in fileFilterManual validation
Error HandlingMulterError with specific codesGeneric errors
MaintenanceActive maintenanceLess 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 multer

Multer 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 production

Security 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.