When a browser submits a form that includes a file input (<input type="file">), it sends the data with a special content type: multipart/form-data. The standard express.json() middleware cannot parse this format. You need a specialized tool, and the most popular one in the Express ecosystem is Multer.

Multer is a middleware for handling multipart/form-data, which is primarily used for uploading files. It adds a file or files object to the request object (req), containing information about the uploaded file(s).

1. Setting Up Multer

First, install multer in your project:

Bash


npm install multer

Next, you need to configure Multer. A common configuration is to tell it where to store the uploaded files on your server.

JavaScript


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

const app = express();

// Configure storage for Multer
const storage = multer.diskStorage({
  // destination is used to determine within which folder the uploaded files should be stored.
  destination: function (req, file, cb) {
    cb(null, './uploads/'); // Store files in an 'uploads' directory
  },
  // filename is used to determine what the file should be named inside the folder.
  filename: function (req, file, cb) {
    // Create a unique filename to avoid overwriting files
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
  }
});

// Initialize Multer with the storage configuration
const upload = multer({ storage: storage });

The diskStorage engine gives you full control over storing files to disk.

2. Creating the Upload Route

Now you can use the upload instance as middleware in the route that will handle the file upload. Multer provides methods like .single(), .array(), and .fields() depending on your needs.

Let's create a route that accepts a single file upload from a form field named profileImage.

JavaScript


// The route will handle POST requests to /upload-profile
// 'upload.single('profileImage')' is the middleware.
// It looks for a file in a form field named 'profileImage'.
app.post('/upload-profile', upload.single('profileImage'), (req, res, next) => {
  // If we get here, the file was successfully uploaded.
  // Multer adds a 'file' object to the request.
  
  if (!req.file) {
    return res.status(400).send('No file was uploaded.');
  }

  console.log('File details:', req.file);
  
  // You can also access form fields if they were sent
  console.log('Body details:', req.body);
  
  res.json({
    message: 'File uploaded successfully!',
    filename: req.file.filename,
    path: req.file.path
  });
});

// A simple error handler for Multer-specific errors
app.use((error, req, res, next) => {
  if (error instanceof multer.MulterError) {
    // A Multer error occurred when uploading.
    return res.status(400).json({ message: 'File upload error', error: error.message });
  }
  // An unknown error occurred.
  next(error);
});

app.listen(3000, () => console.log('Server is running on port 3000'));

When a file is successfully uploaded, req.file will contain metadata about the file, such as its original name, new filename, destination path, size, and MIME type. This allows your application to then process the file, for example, by saving a reference to it in a database.