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

```javascript

app.use(express.json());
```

But file uploads work differently.

Files are usually sent using a format called:

```plaintext
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:

```plaintext

npm install multer
```

Basic Setup :

```javascript

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:

```javascript
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:

```javascript

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:

```javascript

upload.single("image")
```

This means:

*   only one file is expected
    
*   the input field name must be `image`
    

Example frontend form:

```html

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

```javascript

upload.array()
```

Example:

```javascript

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:

```javascript

upload.array("images", 5)
```

means:

*   field name is `images`
    
*   maximum 5 files allowed
    

Frontend example:

```html

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

```javascript

req.files
```

* * *

## Storage configuration basics

By default, Multer generates random file names.

But in real applications, developers usually configure storage manually.

Example:

```plaintext
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:

```plaintext
174689223-profile.png
```

Minimal folder structure:

```javascript
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:

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

This line tells Express:

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

Suppose the folder contains:

```javascript
uploads/
└── profile.png
```

The file becomes accessible at:

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

This URL can be used:

*   inside `<img>` tags
    
*   in frontend applications
    
*   for downloads
    
*   in mobile apps  
    

Complete example:

```javascript

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:

```plaintext
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.
