Skip to main content

Command Palette

Search for a command to run...

Handling File Uploads in Express with Multer

Published
6 min read
Handling File Uploads in Express with Multer

File uploads are one of the most common features in backend applications. Whether users are uploading profile images, PDFs, resumes, or product photos, the server needs a proper way to receive and store those files.

In Express applications, handling uploads is not as straightforward as handling normal JSON data. Files are sent differently by the browser, which is why we need specialized middleware like Multer.

In this article, we’ll understand how file uploads work in Express using Multer, how to upload single and multiple files, and how uploaded files are eventually served to users.


Why file uploads need middleware

When we send normal form data, Express can easily read it using middleware like:


app.use(express.json());

But file uploads work differently.

Files are usually sent using a format called:

multipart/form-data

This format contains:

  • file data

  • form fields

  • metadata

Unlike JSON, Express cannot parse multipart data by default.

That’s why file upload middleware is required.

Without middleware:

  • req.body may work for text fields

  • uploaded files will not be processed correctly

This is where Multer helps.


What Multer is ?

Multer is a middleware for Express that handles multipart/form-data.

Its main job is to:

  • receive uploaded files

  • process them

  • store them on the server

  • provide file information inside the request object

Install Multer:


npm install multer

Basic Setup :


import express from "express";
import multer from "multer";

const app = express();

const upload = multer({
  dest: "uploads/"
});

Here :

  • Multer stores uploaded files inside the uploads folder

  • file information becomes available in the request


Understanding the upload lifecycle

Here’s what happens behind the scenes during a file upload:

Client Selects File
        ↓
Browser Sends multipart/form-data Request
        ↓
Multer Middleware Receives File
        ↓
Multer Processes File
        ↓
File Stored in uploads Folder
        ↓
Request Continues to Route Handler

Multer acts like a middle layer between the incoming request and your route handler.


Handling single file upload

Single file uploads are commonly used for:

  • profile pictures

  • thumbnails

  • resumes

  • documents

Example:


import express from "express";
import multer from "multer";

const app = express();

const upload = multer({
  dest: "uploads/"
});

app.post("/upload", upload.single("image"), (req, res) => {

  res.json({
    message: "File uploaded successfully",
    file: req.file
  });

});

app.listen(3000);

Important part:


upload.single("image")

This means:

  • only one file is expected

  • the input field name must be image

Example frontend form:


<form action="/upload" method="POST" enctype="multipart/form-data">

  <input type="file" name="image" />

  <button type="submit">
    Upload
  </button>

</form>

The enctype="multipart/form-data" is very important. Without it, files will not be sent properly.

After upload:

  • file details are available inside req.file

  • Multer automatically stores the file


Handling multiple file uploads

Sometimes users need to upload multiple files together.

Examples:

  • product gallery images

  • project documents

  • media uploads

Multer provides:


upload.array()

Example:


import express from "express";
import multer from "multer";

const app = express();

const upload = multer({
  dest: "uploads/"
});

app.post("/uploads", upload.array("images", 5), (req, res) => {

  res.json({
    message: "Files uploaded successfully",
    files: req.files
  });

});

Here:


upload.array("images", 5)

means:

  • field name is images

  • maximum 5 files allowed

Frontend example:


<form action="/uploads" method="POST" enctype="multipart/form-data">

  <input type="file" name="images" multiple />

  <button type="submit">
    Upload Files
  </button>

</form>

Uploaded file details are available in:


req.files

Storage configuration basics

By default, Multer generates random file names.

But in real applications, developers usually configure storage manually.

Example:

const storage = multer.diskStorage({

  destination: (req, file, cb) => {
    cb(null, "uploads/");
  },

  filename: (req, file, cb) => {

    const uniqueName =
      Date.now() + "-" + file.originalname;

    cb(null, uniqueName);
  }

});

const upload = multer({ storage });

This configuration helps:

  • organize uploaded files

  • avoid duplicate file names

  • generate readable file names

Example generated file:

174689223-profile.png

Minimal folder structure:

project/
│
├── uploads/
├── server.js
└── package.json

Keeping the structure simple makes uploads easier to understand for beginners.


Serving uploaded files

Uploading files is only part of the process. Users also need access to those uploaded files.

Express provides static middleware for this.

Example:

app.use("/uploads", express.static("uploads"));

This line tells Express:

“Everything inside the uploads folder can be accessed publicly.”

Suppose the folder contains:

uploads/
└── profile.png

The file becomes accessible at:

http://localhost:3000/uploads/profile.png

This URL can be used:

  • inside <img> tags

  • in frontend applications

  • for downloads

  • in mobile apps

Complete example:


import express from "express";
import multer from "multer";

const app = express();

const storage = multer.diskStorage({

  destination: (req, file, cb) => {
    cb(null, "uploads/");
  },

  filename: (req, file, cb) => {

    const uniqueName =
      Date.now() + "-" + file.originalname;

    cb(null, uniqueName);
  }

});

const upload = multer({ storage });

app.use("/uploads", express.static("uploads"));

app.post("/upload", upload.single("image"), (req, res) => {

  const fileUrl =
    `\({req.protocol}://\){req.get("host")}/uploads/${req.file.filename}`;

  res.json({
    message: "Upload successful",
    url: fileUrl
  });

});

app.listen(3000);

Multer middleware execution flow

Here’s the complete execution flow:

User Selects File
        ↓
Browser Sends multipart/form-data Request
        ↓
Multer Middleware Executes
        ↓
File Saved in uploads Folder
        ↓
req.file or req.files Created
        ↓
Route Handler Executes
        ↓
Response Sent to Client

Understanding this flow makes it much easier to debug upload-related issues in Express applications.


Conclusion

File uploads may look simple from the frontend, but a lot happens behind the scenes on the server. Since Express cannot process multipart file data on its own, middleware like Multer becomes essential for handling uploads properly.

Once you understand how Multer receives files, stores them, and passes file information to route handlers, building features like profile image uploads, document systems, or media galleries becomes much easier. Starting with local storage is the best way to learn the complete upload flow before moving toward advanced solutions like cloud storage or CDN-based systems later.