node-js-upload-multiple-files-feature-image

How to upload multiple files in Node.js

In this tutorial, we’re gonna look at way to upload multiple files in Node.js using Multer.

Related Posts:
Upload & resize multiple images in Node.js using Express, Multer, Sharp
How to upload/store images in MongoDB using Node.js, Express & Multer

Upload multiple files in Node.js

Before going to the practice part, I’ll show you a couple of things to notice.

In HTML, we need a form with:
action="/multiple-upload"
enctype="multipart/form-data"
multiple input

<form action="/multiple-upload" method="POST" enctype="multipart/form-data">
    ...
    <input type="file" multiple>
    ...
</form>

With the action "/multiple-upload" and POST method, we use Express Router for the endpoint and controller to handle upload files:

const express = require("express");
const router = express.Router();
const uploadController = require("../controllers/upload");

let routes = app => {
  router.post("/multiple-upload", uploadController.multipleUpload);
  return app.use("/", router);
};

The controller calls a middleware that uses Multer disk storage engine:

var storage = multer.diskStorage({
  destination: function (req, file, callback) {
    callback(null, '/path/to/uploads')
  },
  filename: function (req, file, callback) {
    callback(null, file.fieldname + '-' + Date.now())
  }
});
 
var upload = multer({ storage: storage });

You can see that we have two options here:
destination determines folder to store the uploaded files.
filename determines the name of the file inside the destination folder.

Demo for upload multiple files

Open the app:

node-js-upload-multiple-files-demo-open-browser

Choose the images to upload:

node-js-upload-multiple-files-demo-choose-files

Click on Submit button, if the process is successful, you can see the files in upload folder:

node-js-upload-multiple-files-demo-upload-files-success

If the number of files we choose is larger than 10 (I will show you how to set the limit later):

node-js-upload-multiple-files-demo-upload-files-exceed

Practice

Now this is the time for building our app.

Project Structure

Look at the project structure:

node-js-upload-multiple-files-project-structure

You can see that we have these main parts:
upload: the folder for storing uploaded files.
views/index.html: contains HTML form for user to upload files.
routes/web.js: defines routes for endpoints that is called from views, use controllers to handle requests.
controllers: home.js to show views/index.html, upload.js to handle upload multiple files with middleware.
middleware/upload.js: initializes Multer disk storage engine.
server.js: initializes routes, runs Express app.

Setup Node.js modules

We need to install 2 packages: express and multer.
So run the command:
npm install express multer

Create view

Under views folder, create index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Node.js upload multiple files</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"/>
    <style>
      div.preview-images > img {
        width: 30%;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-sm-8 mt-3">
          <h4>Node.js upload multiple files - bezkoder.com</h4>

          <form action="/multiple-upload" method="POST" enctype="multipart/form-data">
            <div class="form-group">
              <label for="example-input-file"> </label>
              <input type="file" name="multi-files" multiple id="input-multi-files" class="form-control-file border"/>
            </div>
            <button type="submit" class="btn btn-primary">Submit</button>
          </form>
        </div>
      </div>
      <hr />
      <div class="row">
        <div class="col-sm-12">
          <div class="preview-images"></div>
        </div>
      </div>
    </div>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script>
      $(document).ready(function() {
        let imagesPreview = function(input, placeToInsertImagePreview) {
          if (input.files) {
            let filesAmount = input.files.length;
            for (i = 0; i < filesAmount; i++) {
              let reader = new FileReader();
              reader.onload = function(event) {
                $($.parseHTML("<img>"))
                  .attr("src", event.target.result)
                  .appendTo(placeToInsertImagePreview);
              };
              reader.readAsDataURL(input.files[i]);
            }
          }
        };
        $("#input-multi-files").on("change", function() {
          imagesPreview(this, "div.preview-images");
        });
      });
    </script>
  </body>
</html>

The script above helps us show preview of the chosen files. To make things simple, I don’t explain it deeply in the tutorial.

Create middleware for upload multiple files

Inside middleware folder, create upload.js:

const util = require("util");
const path = require("path");
const multer = require("multer");

var storage = multer.diskStorage({
  destination: (req, file, callback) => {
    callback(null, path.join(`${__dirname}/../../upload`));
  },
  filename: (req, file, callback) => {
    const match = ["image/png", "image/jpeg"];

    if (match.indexOf(file.mimetype) === -1) {
      var message = `${file.originalname} is invalid. Only accept png/jpeg.`;
      return callback(message, null);
    }

    var filename = `${Date.now()}-bezkoder-${file.originalname}`;
    callback(null, filename);
  }
});

var uploadFiles = multer({ storage: storage }).array("multi-files", 10);
var uploadFilesMiddleware = util.promisify(uploadFiles);
module.exports = uploadFilesMiddleware;

– We define a storage configuration object, then use multer module to initialize middleware and util.promisify() to make the exported middleware object can be used with async-await.

– To limit the number of files to upload each time, we use array() function with the first parameter is the name of input tag (in html view: <input type="file" name="multi-files">), the second parameter is the max number of files.

– We also check if the file is an image or not using file.mimetype. Then we add the [timestamp]-bezkoder- prefix to the file’s original name to make sure that the duplicates never occur.

If you want to do more, for example, resize the images, please visit this post:
Upload & resize multiple images in Node.js using Express, Multer, Sharp

Create controllers

we create 2 files in controllers folder:

home.js

const path = require("path");

const home = (req, res) => {
  return res.sendFile(path.join(`${__dirname}/../views/index.html`));
};

module.exports = {
  getHome: home
};

upload.js

const upload = require("../middleware/upload");

const multipleUpload = async (req, res) => {
  try {
    await upload(req, res);
    console.log(req.files);

    if (req.files.length <= 0) {
      return res.send(`You must select at least 1 file.`);
    }

    return res.send(`Files has been uploaded.`);
  } catch (error) {
    console.log(error);

    if (error.code === "LIMIT_UNEXPECTED_FILE") {
      return res.send("Too many files to upload.");
    }
    return res.send(`Error when trying upload many files: ${error}`);
  }
};

module.exports = {
  multipleUpload: multipleUpload
};

Define routes

Under routes folder, define routes in web.js:

const express = require("express");
const router = express.Router();
const homeController = require("../controllers/home");
const uploadController = require("../controllers/upload");

let routes = app => {
  router.get("/", homeController.getHome);

  router.post("/multiple-upload", uploadController.multipleUpload);

  return app.use("/", router);
};

module.exports = routes;

There are 2 routes:
- GET: Home page for the upload form.
- POST "/multiple-upload" to call the upload controller.

Create Express app server

The last thing to do is creating an Express server.

server.js

const express = require("express");
const app = express();
const initRoutes = require("./routes/web");

app.use(express.urlencoded({ extended: true }));
initRoutes(app);

let port = 3000;
app.listen(port, () => {
  console.log(`Running at localhost:${port}`);
});

Run the app

On the project root folder, run this command:
node src/server.js

The console shows:

Running at localhost:3000

Now you can open browser with url http://localhost:3000/ to check the result.

Source Code

You can find the complete source code for this example on Github.

Conclusion

Today we’ve learned way to upload multiple files using Multer, we also know how to limit the number of files and only accept image format such as jpeg/png.

You also know way to both upload & resize multiple images in the tutorial:
Upload & resize multiple images in Node.js using Express, Multer, Sharp

Happy learning! See you again.

Further Reading

Leave a Reply

Your email address will not be published. Required fields are marked *