How To Upload Images to the Cloud Using Node.js

In this article, we will go through the steps involved in uploading images to the cloud using Node.js, and we will be using Cloudinary as our cloud storage.

This article will go through the steps involved in uploading images to cloud storage with Node.js, and the cloud storage service we will be using is Cloudinary. When it comes to creating and delivering your digital assets with the least amount of effort,
Cloudinary has you covered with an end-to-end management solution.

This post assumes that you are familiar with the basics of JavaScript and Node.js.

Prerequisites

To follow along, I recommend you have the following:

  • Node version 10 or newer
  • A basic understanding of JavaScript and Node.js
  • An Integrated Development Environment (e.g., Visual Studio Code)

Set Up Your Project

Let’s set up our development environment. Open your terminal and run the following command.

mkdir proEnv
cd proEnv
yarn init

You’ll be asked a few questions, and your answers will be used to generate your package.json file.

Next, we need to install Express—a framework for Node.js.

yarn add express

Let’s create a file named app.js at the root of our project that will serve as an entry point. Navigate to your parent folder and run the command below.

touch app.js

Now, add the following code inside the app.js file:

const

express

=

require

(

"express"

)

const

app

=

express

(

)

const

port

=

9000

app

.

use

(

express

.

json

(

)

)

app

.

listen

(

port

,

(

)

=>

{

console

.

log

(

`Server is running on port:

${

port

}

`

)

}

)

Run the following command in your terminal to start your server:

node app.js

You should see a message in your terminal saying, “Server is running on port 9000.” To automate our server modifications, track changes and restart the server whenever a change occurs, we need to install nodemon as a dev dependency.

yarn add -D nodemon

For the package to work as expected, let’s add a script to our package.json file.

"scripts"

:

{

"dev"

:

"nodemon app.js"

,

"start"

:

"node app.js"

}

Your package.json file should look like this:

{

"name"

:

"image-upload-api"

,

"version"

:

"1.0.0"

,

"description"

:

"Uploading Images to Cloudinary"

,

"main"

:

"app.js"

,

"author"

:

"Sproff"

,

"license"

:

"MIT"

,

"scripts"

:

{

"dev"

:

"nodemon app.js"

,

"start"

:

"node app.js"

}

,

"dependencies"

:

{

"express"

:

"^4.17.1"

}

}

Error Handler

Create a folder at the root of your project called utils. Inside the folder, create a file named errorHandler.js and add the following to it:

class

ErrorHandler

extends

Error

{

constructor

(

statusCode

,

message

)

{

super

(

)

;

this

.

statusCode

=

statusCode

;

this

.

message

=

message

;

}

}

module

.

exports

=

{

ErrorHandler

,

}

;

We created a global error handler to avoid duplicating or rewriting functions that’ll handle errors that may arise while uploading an image or failing to follow a required step. It assigns a status Code and a message depending
on the request.

JSON Web Token (JWT) Implementation Using Node.js

JWTs offer a way to manage security concerns. Learn how to generate a JWT in 4 steps.

Configure a .env File

Require dotenv in your app.js file by adding the following:

require

(

'dotenv'

)

.

config

(

)

Create a file at the root of your project named .env. Go to your Cloudinary dashboard, and copy and paste your Cloud name, API Key and API Secret.

CLOUDINARY_CLOUD_NAME

=

xxx CLOUDINARY_API_KEY

=

xxx CLOUDINARY_API_SECRET

=

xxx

Image Upload Function

At the root of your project, create a folder called controller. Inside the folder, create a file named upload.controller.js and add the following code to it:

const

{

ErrorHandler

}

=

require

(

'../utils/errorHandler'

)

const

uploadImage

=

async

(

req

,

res

,

next

)

=>

{

try

{

res

.

json

(

{

status

:

'success'

,

message

:

'Upload successful'

,

}

)

}

catch

(

error

)

{

next

(

new

ErrorHandler

(

error

.

statusCode

||

500

,

error

.

message

)

)

}

}

module

.

exports

=

{

uploadImage

,

}

We passed three parameters to the uploadImage function. It returns the result of a successful image upload and handles errors with the error handler we created earlier.

Next, we need to install the following packages. Open your terminal and run the following command:

yarn add multer cloudinary dotenv

The command above will install Multer, which is middleware used to handle requests with multipart/form-data header and Cloudinary. Both packages will help us upload our image effectively. We also installed dotenv,
which is an npm package we’ll use to keep our configurations private.

At the root of your project, create a folder named service. Inside the folder, create a file named upload.service.js and add the following to it:

const

multer

=

require

(

"multer"

)

;

const

cloudinary

=

require

(

"cloudinary"

)

;

const

{

ErrorHandler

}

=

require

(

"../utils/errorHandler"

)

;

cloudinary

.

config

(

{

cloud_name

:

process

.

env

.

CLOUDINARY_CLOUD_NAME

,

api_key

:

process

.

env

.

CLOUDINARY_API_KEY

,

api_secret

:

process

.

env

.

CLOUDINARY_API_SECRET

,

}

)

;

const

memoryStorage

=

multer

.

memoryStorage

(

)

;

const

upload

=

multer

(

{

storage

:

memoryStorage

,

}

)

;

const

uploadToCloudinary

=

async

(

fileString

,

format

)

=>

{

try

{

const

{

uploader

}

=

cloudinary

;

const

res

=

await

uploader

.

upload

(

`data:image/

${

format

}

;base64,

${

fileString

}

`

)

;

return

res

;

}

catch

(

error

)

{

throw

new

ErrorHandler

(

500

,

error

)

;

}

}

;

module

.

exports

=

{

upload

,

uploadToCloudinary

,

}

;

Multer allows us to effortlessly transfer files from a browser to the server we desire. Without Multer, we won’t be able to access any data because the request body will be empty.

In the code above, we configure Cloudinary with our credentials stored in the .env file. The process.env property will have access to the keys defined there. We create a function called uploadToCloudinary that accepts
the buffer that needs to be processed before uploading the image to Cloudinary. The upload function serves as middleware that will be called whenever you want to run Multer, and it returns basic information such as the type of storage.
In our case, we’re using MemoryStorage.

Multer allows us to store files dynamically in two ways—DiskStorage and MemoryStorage. We’re using MemoryStorage because it is the most common kind of storage, and it allows us to communicate with our
server while keeping the buffer in memory for future use.

Next, we need to install a package that will allow us to convert between formats—in our case, buffer to data URI. Open your terminal and run the following command:

yarn add datauri

Inside your utils folder, create a file named file.js and add the following to it:

const

DatauriParser

=

require

(

'datauri/parser'

)

const

parser

=

new

DatauriParser

(

)

const

bufferToDataURI

=

(

fileFormat

,

buffer

)

=>

parser

.

format

(

fileFormat

,

buffer

)

module

.

exports

=

{

bufferToDataURI

,

}

The DatauriParser function here acts as a file format conversion passage. We have a file called buffer that needs to be converted to data URI before it can be uploaded to Cloudinary because Cloudinary doesn’t know what
buffer is. The parser will look for the file format .png or .jpg, and convert the buffer to a string.

Now replace the code you have in your upload.controller.js file with this updated one:

const

{

uploadToCloudinary

}

=

require

(

"../service/upload.service"

)

;

const

{

ErrorHandler

}

=

require

(

'../utils/errorHandler'

)

const

{

bufferToDataURI

}

=

require

(

'../utils/file'

)

const

uploadImage

=

async

(

req

,

res

,

next

)

=>

{

try

{

const

{

file

}

=

req

if

(

!

file

)

throw

new

ErrorHandler

(

400

,

'Image is required'

)

const

fileFormat

=

file

.

mimetype

.

split

(

'/'

)

[

1

]

const

{

base64

}

=

bufferToDataURI

(

fileFormat

,

file

.

buffer

)

const

imageDetails

=

await

uploadToCloudinary

(

base64

,

fileFormat

)

res

.

json

(

{

status

:

'success'

,

message

:

'Upload successful'

,

data

:

imageDetails

,

}

)

}

catch

(

error

)

{

next

(

new

ErrorHandler

(

error

.

statusCode

||

500

,

error

.

message

)

)

}

}

module

.

exports

=

{

uploadImage

,

}

We’re importing the bufferToDataURI function in the code above and selecting the file format we want to accept. We destructured the file name from the request body and passed it through a simple check to avoid errors. We get the fileFormat from the file object, split it to select a specific type, and pass the buffer to the bufferToDataURI function, which returns a base64 string.

uploadToCloudinary function here accepts the fileFormat and the base64 string. After a successful upload, res provides a response with all of the details of the image.

Create the Upload Route

Let’s create our route. At the root of your project, create a folder named routes, and inside it, create a file named upload.routes.js. Add the following to the file:

const

{

Router

}

=

require

(

'express'

)

const

{

uploadImage

}

=

require

(

'../controller/upload.controller'

)

const

{

upload

}

=

require

(

'../service/upload.service'

)

const

router

=

Router

(

)

router

.

post

(

'/'

,

upload

.

single

(

'image'

)

,

uploadImage

)

module

.

exports

=

router

Here we destructured the Express router and assigned it to a variable to generate a post request. We’re using the Multer middleware, and upload.single simply uploads a single image. There are other methods for uploading images, such
as upload.array, which can upload multiple images.

Now, let’s import our newly created route into our app.js file.

const

express

=

require

(

"express"

)

;

require

(

"dotenv"

)

.

config

(

)

;

const

app

=

express

(

)

;

const

uploadRouter

=

require

(

'./routes/upload.routes'

)

const

port

=

process

.

env

.

PORT

||

9000

;

app

.

use

(

express

.

json

(

)

)

;

app

.

use

(

'/upload'

,

uploadRouter

)

app

.

listen

(

port

,

(

)

=>

{

console

.

log

(

`Server running on port:

${

port

}

`

)

;

}

)

;

Screenshot of Cloudinary Media Library

To view the image you just uploaded, log in to your Cloudinary account and check your media library.

Conclusion

This post covered the steps involved in uploading images directly to Cloudinary using Express.js and Multer. We saw how easy it was to integrate Cloudinary with these third-party libraries.