Skip to content

Node.js File Upload — Complete Guide to Handling File Uploads

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Node.js File Upload. We cover key concepts, practical examples, and best practices to help you master this topic.

Node.js file upload handling involves receiving multipart form data, validating file types and sizes, storing files locally or in the cloud, and processing them for various use cases.

What You'll Learn

By the end of this tutorial, you'll use multer for file uploads, validate file types and sizes, store files locally and in cloud storage, Process images with sharp, and secure upload endpoints.

Why File Upload Matters

Most web applications need file uploads: profile pictures, document attachments, image galleries, and data imports. Secure and efficient file handling is essential for user-facing features.

Real-World Use

A document management system lets users upload PDFs, images, and spreadsheets. multer validates file types, limits sizes to 10MB, and stores files in AWS S3 with unique filenames.

File Upload Learning Path

flowchart LR
  A[Authorization] --> B[File Upload]
  B --> C[Caching]
  C --> D[Docker]
  D --> E[Deployment]
  A --> F{You Are Here}
  style F fill:#f90,color:#fff

Multer Setup

npm install multer
import multer from "multer";
const upload = multer({ dest: "uploads/" });
app.post("/upload", upload.single("file"), (req, res) => {
  res.json({
    message: "File uploaded",
    file: req.file  // { fieldname, originalname, encoding, mimetype, size, path }
  });
});

Storage Configuration

import multer from "multer";
import path from "node:path";
const storage = multer.diskStorage({
  destination: (req, file, cb) => cb(null, "uploads/"),
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + "-" + uniqueSuffix + path.extname(file.originalname));
  }
});
const upload = multer({ storage });

File Validation

const ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp", "application/pdf"];
const MAX_SIZE = 5 * 1024 * 1024;  // 5MB
const upload = multer({
  storage,
  limits: { fileSize: MAX_SIZE },
  fileFilter: (req, file, cb) => {
    if (!ALLOWED_TYPES.includes(file.mimetype)) {
      cb(new Error("Invalid file type"), false);
      return;
    }
    cb(null, true);
  }
});
app.post("/upload", (req, res) => {
  upload.single("file")(req, res, (err) => {
    if (err instanceof multer.MulterError) return res.status(400).json({ error: err.message });
    if (err) return res.status(400).json({ error: err.message });
    res.json({ message: "Uploaded", file: req.file });
  });
});

Multiple File Uploads

app.post("/upload-multiple", upload.array("files", 5), (req, res) => {
  res.json({ files: req.files.map(f => ({ name: f.originalname, size: f.size })) });
});

Image Processing with Sharp

npm install sharp
import sharp from "sharp";
app.post("/upload-image", upload.single("image"), async (req, res) => {
  const inputPath = req.file.path;
  const outputPath = `uploads/resized-${req.file.filename}`;
  await sharp(inputPath)
    .resize(800, 600, { fit: "inside", withoutEnlargement: true })
    .webp({ quality: 80 })
    .toFile(outputPath);
  res.json({ original: req.file.filename, thumbnail: outputPath });
});

Cloud Storage with S3

npm install @aws-sdk/client-s3 multer-s3
import { S3Client } from "@aws-sdk/client-s3";
import multerS3 from "multer-s3";
const s3 = new S3Client({ region: process.env.AWS_REGION });
const upload = multer({
  storage: multerS3({
    s3,
    bucket: "my-uploads",
    acl: "public-read",
    metadata: (req, file, cb) => cb(null, { fieldName: file.fieldname }),
    key: (req, file, cb) => cb(null, `${Date.now()}-${file.originalname}`)
  }),
  limits: { fileSize: 10 * 1024 * 1024 }
});

Common Mistakes

1. Not Validating File Types on Server

Client-side validation is easily bypassed. Always validate mimetype and extension on the server.

2. Using Original Filenames

Original filenames may contain path traversal sequences or special characters. Generate unique filenames on the server.

3. No File Size Limit

Without size limits, users can upload massive files that fill disk space and crash the server. Always set limits.

4. Storing Uploads in the Public Directory

Uploads in the static directory are publicly accessible by URL. Store them outside the web root or use signed URLs.

5. Not Handling Upload Errors Gracefully

Failed uploads (disk full, connection lost) must return clear error messages and clean up partial files.

Practice Questions

1. What is multer?

Multer is an Express middleware for handling multipart/form-data, primarily used for file uploads. It processes incoming files and makes them available as req.file or req.files.

2. How do you restrict file types in multer?

Pass a fileFilter function to multer configuration. Check file.mimetype against an allowed list and call cb(null, true) or cb(new Error(...), false).

3. How do you limit file size in multer?

Set the limits.fileSize option in multer configuration. Size is in bytes. Exceeding the limit throws a MulterError.

4. Why generate unique filenames for uploads?

To prevent overwriting existing files, avoid filename collisions, and prevent path traversal attacks from malicious filenames.

5. Challenge: Create an upload endpoint that accepts images, resizes them, and stores both original and thumbnail.

const upload = multer({ dest: "uploads/" });
app.post("/upload", upload.single("image"), async (req, res) => {
  const thumbPath = `uploads/thumb-${req.file.filename}`;
  await sharp(req.file.path).resize(200, 200).toFile(thumbPath);
  res.json({ original: req.file.path, thumbnail: thumbPath });
});

FAQ

Can multer handle other form fields alongside files?

Yes. Access non-file fields via req.body (requires enctype='multipart/form-data').

How do I handle large file uploads?

Increase limits.fileSize, use streaming, consider chunked uploads. For very large files (>100MB), use direct-to-S3 uploads.

What is the difference between multer.diskStorage and multer.memoryStorage?

diskStorage saves files to disk. memoryStorage keeps files in Buffer (memory). memoryStorage is useful for cloud uploads.

How do I serve uploaded files securely?

Store outside public directory. Create a download route with authentication that reads and streams the file.

What is the maximum upload size in Express?

Default body parser limit is 100kb for JSON. Multer handles multipart separately. Set both appropriately for your use case.

Mini Project: Avatar Upload

Build a profile avatar upload endpoint with image validation and resizing.

import multer from "multer";
import sharp from "sharp";
import path from "node:path";
const storage = multer.memoryStorage();
const upload = multer({
  storage,
  limits: { fileSize: 2 * 1024 * 1024 },
  fileFilter: (req, file, cb) => {
    if (!file.mimetype.startsWith("image/")) return cb(new Error("Images only"), false);
    cb(null, true);
  }
});
app.post("/api/avatar", authenticate, upload.single("avatar"), async (req, res) => {
  const buffer = await sharp(req.file.buffer).resize(150, 150).png().toBuffer();
  const filename = `avatar-${req.user.id}.png`;
  await fsPromises.writeFile(`uploads/${filename}`, buffer);
  await db.users.update(req.user.id, { avatar: filename });
  res.json({ avatar: filename });
});

What's Next

Node.js Caching Redis Node.js Docker Node.js Deployment

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro