How to upload, display and save images using node.js and express

277,291

First of all, you should make an HTML form containing a file input element. You also need to set the form's enctype attribute to multipart/form-data:

<form method="post" enctype="multipart/form-data" action="/upload">
    <input type="file" name="file">
    <input type="submit" value="Submit">
</form>

Assuming the form is defined in index.html stored in a directory named public relative to where your script is located, you can serve it this way:

const http = require("http");
const path = require("path");
const fs = require("fs");

const express = require("express");

const app = express();
const httpServer = http.createServer(app);

const PORT = process.env.PORT || 3000;

httpServer.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

// put the HTML file containing your form in a directory named "public" (relative to where this script is located)
app.get("/", express.static(path.join(__dirname, "./public")));

Once that's done, users will be able to upload files to your server via that form. But to reassemble the uploaded file in your application, you'll need to parse the request body (as multipart form data).

In Express 3.x you could use express.bodyParser middleware to handle multipart forms but as of Express 4.x, there's no body parser bundled with the framework. Luckily, you can choose from one of the many available multipart/form-data parsers out there. Here, I'll be using multer:

You need to define a route to handle form posts:

const multer = require("multer");

const handleError = (err, res) => {
  res
    .status(500)
    .contentType("text/plain")
    .end("Oops! Something went wrong!");
};

const upload = multer({
  dest: "/path/to/temporary/directory/to/store/uploaded/files"
  // you might also want to set some limits: https://github.com/expressjs/multer#limits
});


app.post(
  "/upload",
  upload.single("file" /* name attribute of <file> element in your form */),
  (req, res) => {
    const tempPath = req.file.path;
    const targetPath = path.join(__dirname, "./uploads/image.png");

    if (path.extname(req.file.originalname).toLowerCase() === ".png") {
      fs.rename(tempPath, targetPath, err => {
        if (err) return handleError(err, res);

        res
          .status(200)
          .contentType("text/plain")
          .end("File uploaded!");
      });
    } else {
      fs.unlink(tempPath, err => {
        if (err) return handleError(err, res);

        res
          .status(403)
          .contentType("text/plain")
          .end("Only .png files are allowed!");
      });
    }
  }
);

In the example above, .png files posted to /upload will be saved to uploaded directory relative to where the script is located.

In order to show the uploaded image, assuming you already have an HTML page containing an img element:

<img src="/image.png" />

you can define another route in your express app and use res.sendFile to serve the stored image:

app.get("/image.png", (req, res) => {
  res.sendFile(path.join(__dirname, "./uploads/image.png"));
});
Share:
277,291
user1602123
Author by

user1602123

Updated on July 07, 2020

Comments

  • user1602123
    user1602123 almost 4 years

    I need to upload an image, and display it, as well as save it so that I don't lose it when I refresh the localhost. This needs to be done using an "Upload" button, which prompts for a file-selection.

    I am using node.js and express for the server-side code.

    • Emad Baqeri
      Emad Baqeri almost 3 years
      you can also use multer for file or image uploading and sharp js for image processing and doing resizing or compressing and other things on images
  • mattdlockyer
    mattdlockyer over 10 years
    You sir are a gentleman and a scholar
  • Scott Meyers
    Scott Meyers about 9 years
    For anybody looking to access 'req.files' or 'req.body', body-parser now only handles JSON, check out github.com/expressjs/multer
  • Niklas Zantner
    Niklas Zantner over 8 years
    as "app.use(express.bodyParser({uploadDir:'...'}));" is not longer working one should use "app.use(bodyParser({uploadDir:'...'}));". therefor body-parser has to be added via npm and added to the file you using it in via "var bodyParser = require('body-parser');"
  • Muhammad Shahzad
    Muhammad Shahzad about 8 years
    how we can do this in express 4?
  • Gaurav51289
    Gaurav51289 about 8 years
    @fardjad What if I have angular in between ?
  • codeinprogress
    codeinprogress almost 8 years
    @fardjad the req.files.file.path gives me "cannot read property 'file' of undefined" error. Doing everything you did except the express.bodyparser() since I am using express 4.x I am doing app.use(bodyParser.urlencoded({'extended':'true'}));
  • Yuvaraj V
    Yuvaraj V about 7 years
    For express 4 use multer middle ware for file upload..
  • uruapanmexicansong
    uruapanmexicansong over 6 years
    To show we can use a public file path. /static/avatars/18746365356.png
  • Matt West
    Matt West about 5 years
    One of the most thorough answers I've seen here. Awesome.
  • principiorum
    principiorum over 4 years
    for those who get ENOENT: no such file or directory, rename error, you can install fs-extra and use fs.ensureDir to ensure the target path is exist.
  • Rohit Gupta
    Rohit Gupta over 3 years
    This answer has drastically reduced my time to implement. Thanks a lot sir. 🙏