Simple and Fast File Upload in Node.js with Express and Multer

Simple and Fast File Upload in Node.js with Express and Multer

File uploading is a very common feature in today's web applications. In this post, we will see how we can upload files in Node.js using a simple middleware called Multer for Express.

Project setup

In your terminal run

mkdir file-upload
cd file-upload
touch app.js index.html

Inside file-upload create a folder called uploads, this is where we will store all uploaded files.

mkdir uploads

Next install Express and Multer.

npm init -y
npm install express multer

Technologies

Express: Minimal framework for building web applications in Node.js.
Multer: Middleware for Node.js handling multipart-form-data. It's mainly used for file upload.

Implemenation

In index.html add the following.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>File upload</title>
    <style>
      body {
        background: #f1f1f1;
        margin: 0;
      }

      .filelist {
        list-style-type: none;
        padding: 0;
      }

      .container {
        margin: 0 auto;
        max-width: 600px;
        padding: 30px 20px;
        background: #fff;
      }

      .submit-btn {
        margin-top: 30px;
        cursor: pointer;
        font-size: 18px;
        font-weight: 700;
        color: white;
        background-color: black;
        display: block;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>File Upload in Node.js</h1>
      <form method="post" action="fileUpload" enctype="multipart/form-data">
        <input name="file" id="filesToUpload" type="file" />
        <button type="submit" class="submit-btn">Submit</button>
      </form>
    </div>
  </body>
</html>

First, we add some basic styling. Then we create the form to handle uploading of files.

method attribute specifies what kind of request we are doing and action is where the request will go. enctype="multipart/form-data" is very important without this Multer will just ignore the request.

On the documentation page for Multer, they have written "NOTE: Multer will not process any form which is not multipart (multipart/form-data)."

For the input it's of type file and this will open a file dialog, name is set to file (can be set to anything) this is where Multer will look for our file.

In app.js add this code.

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

const app = express();
const port = 3000;

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, './uploads');
    },
    filename: (req, file, cb) => {
      cb(null, `${Date.now()}-${file.originalname}`);
    }
});

const upload = multer({storage});

app.get('/', (req, res) => res.sendFile(path.join(__dirname+'/index.html')));

app.post('/fileUpload', upload.single('file'), (req, res) => {
    res.send('file uploaded');
});

app.listen(port, () => console.log(`Example app listening on port ${port}!`));

We first import all dependencies and create an express app. After that, we call multer.diskStorage with a config object and pass it two functions.

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

destination tells Multer in what folder all uploaded files should be stored.

 filename: (req, file, cb) => {
      cb(null, `${Date.now()}-${file.originalname}`);
}

filename specifies what the file should be called. We generate the name by getting the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC and append it to the originalname.

File argument is information about the file that Multer inject. If we would print it, it would look something like this.

multer-argument

const upload = multer({storage});

Mutler accepts an options object, we pass it our diskStorage configuration.

app.get('/', (req, res) => res.sendFile(path.join(__dirname+'/index.html')));

app.post('/fileUpload', upload.single('file'), (req, res) => {
    res.send('file uploaded');
});

app.listen(port, () => console.log(`Example app listening on port ${port}!`));

First we create a route for rendering index.html.

Next, we add a route for uploading the files, here we apply upload.single('file'), the argument should be the same as we specified in our input as name, in this case "file".

Last line we start Express and set it to listen to the port variable.

To try it out, go to your terminal and run

node app.js

Visit http://localhost:3000 and you should see the form.

form-upload

Select a file and then press submit. You should then be redirected to a new page that says "file uploaded." If you now look in the uploads folder it should now contain the selected file.

How to upload multiple files?

Start with creating a new route in app.js.

app.post('/multi-upload', upload.array('files', 5), (req, res) => {
    res.send('file uploaded');
});

(Don't forget to restart the server by killing it with ctrl c and run node app.js)

Here we specify that we will upload an array called files with a limit of 5 files.

In index.html update content in the body to this.

 <div class="container">
      <h1>File Upload in Node.js</h1>
      <form method="post" action="multi-upload" enctype="multipart/form-data">
        <input name="files" id="filesToUpload" type="file" multiple />
        <ul class="filelist" id="fileList"></ul>
        <button class="submit-btn">Submit</button>
      </form>
  </div>

We update action to be multi-upload same path as we specifiec for our route. The multiple attribute is added to our input, this makes it possible to select multiple files. We change name to be files to indicate in the code we expect multiple files. The last thing we did was to add a ul list, this will display all selected files.

In the bottom of the body in index.html add this snippet.

  <script>
    const input = document.getElementById("filesToUpload");
    const list = document.getElementById("fileList");

    input.onchange = () => {
      while (list.hasChildNodes()) {
        list.removeChild(ul.firstChild);
      }
      
      if (input.files.length > 1) {
        for (let file of input.files) {
          const li = document.createElement("li");
          li.innerHTML = file.name;
          list.append(li);
        }
      }
    }
  </script>

We set up an event listener on the input. When the input is changed we clear our list after that we append every selected file if more then 1 file is selected.

Try it out and select multiple files, you should now have something like this.

form-upload-multiple-files

Summary

With the help of express and Multer we have implemented file upload with single and multiple files. I hope you saw how easy it was and how little code is needed. Visit multer to find out how you can customize your file upload more.