Skip to main content

Command Palette

Search for a command to run...

Handling File Uploads in Express with Multer

Updated
•5 min read•View as Markdown

If you are building a full-stack application, eventually, you are going to need users to upload something. Whether it is a profile picture, a PDF resume, or a gallery of product images, handling file uploads can feel like dark magic the first time you try it.

You might try sending a file to your Express server just like you send regular JSON data, only to find that your server has absolutely no idea what to do with it.

Let's break down exactly why that happens, how the multipart/form-data concept works, and how to use a tool called Multer to make file uploads incredibly easy.

1. Why Express Can't Handle Files Out of the Box

Imagine you are sending information to a friend. Sending regular text data (like a username or password in JSON) is like sending a postcard. It is lightweight, the text is right there on the back, and the mail carrier (Express) can read it instantly.

Sending a file (like an image or a video) is entirely different. It is like shipping a heavy, sealed package. You can't just stick a postcard stamp on a package and expect it to arrive. You need a special shipping method.

On the web, this special shipping method is called multipart/form-data. When an HTML form sends a file, it chops the data into "multiple parts" so it can be streamed securely over the internet.

By default, Express only knows how to read postcards (JSON or URL-encoded text). If you hand it a heavy package (multipart/form-data), it simply ignores it. We need a dedicated "package handler" to open the box, take the file out, and put it somewhere safe.

That is where middleware comes in.

2. Enter Multer: The Package Handler

Multer is a middleware specifically designed for Express.js. Its only job is to handle multipart/form-data.

When a user submits a file, Multer intercepts the request before it reaches your main route logic. It reads the incoming file stream, saves the file to a folder on your computer, and then attaches a neat little summary of the file to the req object so you can use it.

The Upload Lifecycle

  1. User uploads profile.jpg via a form.

  2. The request hits your Express server.

  3. Multer intercepts it. Multer saves the image to a folder (e.g., /uploads).

  4. Multer creates an object with the file's details (filename, size, path) and attaches it to req.file.

  5. Your route handler runs, and you can now save the file path to your database.

3. Basic Setup & Storage Configuration

Before we upload anything, we need to install Multer:

npm install multer

Next, we need to tell Multer where to put the files and what to name them. We do this using multer.diskStorage.

const express = require('express');
const multer = require('multer');
const path = require('path');

const app = express();

// Configure where and how the files are saved
const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        // Tell Multer to save files in the 'uploads' folder
        cb(null, 'uploads/'); 
    },
    filename: (req, file, cb) => {
        // Give the file a unique name (timestamp + original name)
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
        cb(null, uniqueSuffix + '-' + file.originalname);
    }
});

// Initialize Multer with our storage engine
const upload = multer({ storage: storage });

(Note: Make sure you actually create a folder named uploads in your project directory, or Node will throw an error!)

4. Handling a Single File Upload

Now that Multer is configured, we can inject it into our routes as middleware. If we are expecting a single file (like an avatar), we use upload.single('fieldName').

The string inside .single() MUST exactly match the name attribute of the input field in your frontend form.

// The middleware upload.single('avatar') runs first
app.post('/upload-profile', upload.single('avatar'), (req, res) => {
    
    // If Multer failed, req.file will be undefined
    if (!req.file) {
        return res.status(400).send('No file uploaded.');
    }

    // Multer attached the file info to req.file
    console.log(req.file);
    
    /* 
      req.file looks like this:
      {
        fieldname: 'avatar',
        originalname: 'my-photo.jpg',
        encoding: '7bit',
        mimetype: 'image/jpeg',
        destination: 'uploads/',
        filename: '16987654321-my-photo.jpg',
        path: 'uploads\\16987654321-my-photo.jpg',
        size: 102450
      }
    */

    res.send(`File uploaded successfully! Saved as ${req.file.filename}`);
});

5. Handling Multiple File Uploads

What if you are building a product page and need to upload 5 images at once? Instead of .single(), we use upload.array('fieldName', maxCount).

// Accept an array of files from the 'gallery' input, up to a max of 5 files
app.post('/upload-gallery', upload.array('gallery', 5), (req, res) => {
    
    if (!req.files || req.files.length === 0) {
        return res.status(400).send('No files uploaded.');
    }

    // Notice it is req.files (plural) now! It is an array of objects.
    console.log(req.files);

    res.send(`${req.files.length} files uploaded successfully!`);
});

6. Serving the Uploaded Files

Uploading files is only half the battle. If a user uploads a profile picture, they expect to see it on their screen.

By default, Express protects all the folders in your project. If someone tries to visit http://localhost:3000/uploads/my-photo.jpg, Express will block them and return a 404 error.

You have to explicitly tell Express to make your uploads folder public. We do this using the built-in express.static middleware.

// Serve the 'uploads' directory publicly
app.use('/uploads', express.static('uploads'));

Now, if you have a file named 123-avatar.jpg inside your uploads folder, your frontend can display it normally using an image tag: <img src="http://localhost:3000/uploads/123-avatar.jpg" />

Summary

Handling files doesn't have to be complicated if you understand the flow:

  1. Files travel as multipart/form-data, which Express ignores by default.

  2. Multer is the middleware that intercepts, reads, and saves these files to your server's disk.

  3. Use upload.single() for one file, which attaches data to req.file.

  4. Use upload.array() for multiple files, which attaches an array to req.files.

  5. Expose your upload folder using express.static so the frontend can actually display the images.

Stay Tune for next Blog! Happy Coding!

1 views