This tutorial shows you how to upload, display and save images in node.js using the express-fileupload
, formidable
, and multer
modules. Apart from the file upload modules, we will use the express
server, ejs
templating engine, and nodemon
to restart the server.
It assumes you want to take a file input on a form, upload it to a Node.js server, and save it before displaying it as a static asset.
Let's get started.
Setup Lab environment
Create the file structure.
fileUploads/
├── expressUpload
│  ├── index.js
│  ├── public
│  │  ├── images
│  │  └── style.css
│  └── views
│  ├── layout.ejs
│  └── upload.ejs
├── formidable
│  ├── index.js
│  ├── public
│  │  ├── images
│  │  └── style.css
│  └── views
│  ├── layout.ejs
│  └── upload.ejs
└── multer
├── index.js
├── public
│  ├── images
│  └── style.css
└── views
├── layout.ejs
└── upload.ejs
as follows
# main directory
mkdir fileUploads && cd fileUploads
# subdirectories
mkdir expressUpload formidable multer
# public
mkdir expressUpload/public formidable/public multer/public
mkdir expressUpload/public/images formidable/public/images multer/public/images
touch expressUpload/public/style.css formidable/public/style.css multer/public/style.css
# views
mkdir expressUpload/views formidable/views multer/views
touch expressUpload/views/layout.ejs formidable/views/layout.ejs multer/views/layout.ejs
touch expressUpload/views/upload.ejs formidable/views/upload.ejs multer/views/upload.ejs
# script file
touch expressUpload/index.js formidable/index.js multer/index.js
On Windows, you can run the same commands on Git Bash. Next, include the following code in each subdirectory: expressUpload
, formidable
, and multer
.
public ->Â images ->Â style.css
body {
background-color: #f7f8fc;
}
views ->Â layout.ejs
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="/style.css">
<title>Uploads</title>
</head>
<body>
<%- body %>
</body>
</html>
We link Bootstrap 5 for basic styling of the upload.ejs
page.
views -> upload.ejs
<div class="container">
<form class="w-50 mx-auto my-3" action="/uploads" method="post" enctype="multipart/form-data">
<div class="mb-3">
<input class="form-control" type="file" name="upload" required>
</div>
<button class="btn btn-primary">Upload</button>
</form>
<div class="container">
<div class="row">
<div class="col my-3">
<div class="card" style="width: 18rem;">
<img src="/images/image1.jpg" class="card-img-top" alt="Image">
</div>
</div>
<div class="col my-3">
<div class="card" style="width: 18rem;">
<img src="/images/image2.jpg" class="card-img-top" alt="Image">
</div>
</div>
<div class="col my-3">
<div class="card" style="width: 18rem;">
<img src="/images/image3.jpg" class="card-img-top" alt="Image">
</div>
</div>
</div>
</div>
</div>
post
, encoding type multipart/form-data
, and file's name
in the form.Download the (image1, image2, and image3) images. We will be uploading them to the public/images
folder of the server.
Using the express.static()
function implemented in each index.js
file, we will let the frontend to fetch images from the server automatically.
Here is how to implement each module in the index.js
file.
How to upload, display and save images in node.js examples
Example~1: How to upload, display and save images in node.js using the express-upload module
Initialize a package.json
file, then install the third-party packages.
cd expressUpload
npm init -y
npm i ejs express express-ejs-layouts express-fileupload
npm i -g nodemon
Update package.json
to use nodemon
"start": "nodemon index"
and index.js
to upload accept image uploads
const express = require('express')
const ejsLayouts = require('express-ejs-layouts')
const fileUpload = require('express-fileupload')
const path = require('path')
const app = express()
app.use(fileUpload())
app.set('view engine', 'ejs')
app.use(ejsLayouts)
app.use(express.static('public'))
app.use(express.urlencoded({ extended: true }))
//routes
app.get('/', (req, res) => res.render('upload'))
app.post('/uploads', function(req, res) {
const file = req.files.upload
const filePath = path.join(__dirname, 'public', 'images', `${file.name}`)
file.mv(filePath, err => {
if (err) return res.status(500).send(err)
res.redirect('/')
})
})
app.listen(3000)
We grab the incoming (image) file details and store them in the file
variable.
const file = req.files.upload
From the file's name specified in the form input, we create the destination directory and hold it in the filePath
variable.
const filePath = path.join(__dirname, 'public', 'images', `${file.name}`)
Using the mv()
function (provided by the module), we upload the image to the specified destination.
file.mv(filePath, err => {
if (err) return res.status(500).send(err)
res.redirect('/')
})
Lastly, we run the callback function checking if there was an error uploading the image to the server. Otherwise, we redirect the user to the home page.
Start the server.
npm start
Open port 3000 on the browser and try uploading an image.
Before uploading an image
After uploading the 3 images
Example~2: How to upload, display and save images in node.js using the formidable module
Initialize a package.json
then install the third-party packages.
cd ..
cd formidable
npm init -y
npm i ejs express express-ejs-layouts formidable
Update package.json
to use nodemon
"start": "nodemon index"
and index.js
const express = require('express')
const ejsLayouts = require('express-ejs-layouts')
const formidable = require('formidable')
const path = require('path')
const fs = require('fs')
const app = express()
app.set('view engine', 'ejs')
app.use(ejsLayouts)
app.use(express.static('public'))
app.use(express.urlencoded({ extended: true }))
//routes
app.get('/', (req, res) => res.render('upload'))
app.post('/uploads', (req, res) => {
const form = new formidable.IncomingForm()
const filePath = path.join(__dirname, 'public', 'images')
form.uploadDir = filePath
form.parse(req, async (err, fields, files) => {
if (err) res.send("Error parsing the files")
const file = files.upload
const fileName = file.originalFilename
fs.renameSync(file.filepath, path.join(filePath, fileName))
res.redirect("/")
})
})
app.listen(4000)
We create an instance of the form data (from the client-side) and store the result in the form variable.
const form = new formidable.IncomingForm()
Using the object's uploadDir
attribute, we tell the module to store the uploaded file in the public directory's images
directory referenced by the filePath
variable. Using other attributes like multiples
and maxFileSize
, we could control file size and whether we need multiple uploads.
Next, we parse the files in the object's parse() method, which takes the request object and a callback function returning error
, fields
, and files
objects.
form.parse(req, async (err, fields, files) => {} )
We then store the filename in a format we want (.jpg
) by renaming the initially saved file.
const file = files.upload
const fileName = file.originalFilename
fs.renameSync(file.filepath, path.join(filePath, fileName))
Lastly, we redirect the user to the home page.
res.redirect("/")
Start the server.
npm start
Open port 4000 on the browser and upload the three images.
Example~3: How to upload, display and save images in node.js using the multer module
Initialize a package.json
then install the third-party packages.
cd ..
cd multer
npm init -y
npm i ejs express express-ejs-layouts multer
Update package.json
to accommodate nodemon
"start": "nodemon index"
and index.js
// import modules
const express = require('express')
const ejsLayouts = require('express-ejs-layouts')
const multer = require('multer')
const path = require('path')
// create server
const app = express()
// configure templating engine
app.set('view engine', 'ejs')
app.use(ejsLayouts)
// make public directory's files static
app.use(express.static('public'))
// handle form data
app.use(express.urlencoded({ extended: true }))
// Configure multer
const storageEngine = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, path.join(__dirname, 'public', 'images'))
},
filename: (req, file, callback) => {
callback(null, file.originalname)
}
})
const upload = multer({ storage: storageEngine })
// routes
app.get('/', (req, res) => res.render('upload'))
app.post('/uploads', upload.single('upload'), async (req, res) => {
res.redirect("/")
})
app.listen(5000)
The diskStorage()
function allows us to store files on the disk. We pass it to two objects, each accepting the request object, file, and a callback function. The callback checks for any error (null) before handling file saving as follows:
destination
: We tell the module to save images in the images directory inside the public directory.filename
: We tell multer
to save the image's original name in the specified destination.
We then ship the packed destination and filename to multer
and run the middleware before hitting the /uploads
endpoint.
Start the server.
npm start
Open port 5000 on the browser and upload the images.
Conclusion
Knowing how to upload, display and save images in node.js is a key step toward handling images in a Node.js server. After uploading the images, you can save them on the server, upload them to a CDN or save them in a database.
This tutorial walked you through one of the most challenging parts: uploading images to a Node.js server. You saw how to upload images with the express-fileupload
, formidable
and multer
modules. Next, you saved the images in a public directory and displayed them on the landing page.
You can find the complete code on GitHub.