Skip to content

Upload Images to Cloudinary with Netlify Functions

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 article will go through the steps involved in uploading images to Cloudinary using serverless functions.

With serverless functions, we can write backend or server-side code without the burden of managing servers. In this article, we will be using Netlify functions, and it allows us to create, deploy, and manage serverless lambda functions without requiring an AWS account. Still, under the hood, Netlify functions are powered by AWS Lambda.

This article assumes—or hopes is perhaps a better word—that you are familiar with the basics of JavaScript and React.js.

Here is a link to the demo on CodeSandbox and the source code on GitHub.

To follow this article, I recommend you have the following:

  • Node version 10 or newer.
  • Basic understanding of JavaScript, Serverless Functions, and Node.js.
  • Integrated Development Environment (e.g., Visual studio code).

Open your terminal and run the following command to create a React application in a folder called imageUploader.

    npx create-react-app imageuploader

Now let’s install the dependencies we will need for this project.

    npm install netlify cloudinary dotenv

The next step is to install the Netlify CLI tool. Run the following command to install it as a dev dependency.

    npm install -D netlify-cli

Following that, we need to create a folder where our Netlify can find serverless functions. Create a folder called functions at the root of your project. Create a file called uploadImage.js within that folder and add the following code to it. This will be our serverless function.

    exports.handler = async function(event, context) {
      return {
        statusCode: 200,
        body: JSON.stringify({ message: 'Hello World' })
Code language: JavaScript (javascript)

We will update the logic for the upload functionalities later, but this is basic enough to show that the API is working for now.

Let’s create a netlify.toml file at the root of our project. This is a config file for Netlify, and it will be used to specify how Netlify should build our site. Add the following to the file.

    functions = "functions"
Code language: JavaScript (javascript)

functions is the directory where our serverless function is located.

To access a local development server that supports serverless functions, we need to add a script to the package.json file.

Add the following to the scripts section of your package.json file.

    "dev": "netlify dev"
Code language: JavaScript (javascript)

We’re all set up! Run the following command in your terminal to start up your local development server.

    npm run dev

Once the server successfully runs, open the link below in your browser to test the serverless function.


Let’s work on the interface we’ll use to upload images. Open your App.css file and replace whatever is inside with the following.

    .App {
      width: 100%;
      max-width: 450px;
      min-height: 400px;
      background-color: #f2f2f2;
      margin: auto;
      margin-top: 5rem; 
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    h4 {
      text-align: center;
      font-size: 1.5rem;
      font-weight: 600;
    .uploadBtn {
      padding: 1rem 2.5rem;
      background-color: #370aa0;
      color: #fff;
      cursor: pointer;
      margin-bottom: 1rem;
    .imgUrl {
      width: 100%;
      height: auto;
Code language: CSS (css)

Open your App.js file and add the following to it.

    import './App.css';
    function App() {
      return (
        <div className="App">
          <h4>Upload Images</h4>
          <input id="upload" type="file" hidden />
          <label className="uploadBtn" htmlFor="upload">Upload Image</label>
    export default App;
Code language: JavaScript (javascript)

You can test the React app by heading to the following localhost URL:


The output in the browser should look like this.

Now let’s set up our environment variables. Create a root-level file called .env and add the following variable to it.

    CLOUDINARY_NAME="cloud name"
    CLOUDINARY_API_KEY="api key"
    CLOUDINARY_API_SECRET="api secret"
Code language: JavaScript (javascript)

We need to get the values for the variables from Cloudinary. Log in to your Cloudinary account or create a free account if you do not have one already.

After you register and log in to your account, you will be directed to your Dashboard page. The account details section on the dashboard page shows your cloud name, API Key, and API Secret. Copy and add the keys to the environmental variables.

Now let’s update our serverless function. Update your uploadImage.js file with the following.

    const cloudinary = require("cloudinary").v2;
    const dotenv = require("dotenv");
      cloud_name: process.env.CLOUDINARY_NAME,
      api_key: process.env.CLOUDINARY_API_KEY,
      api_secret: process.env.CLOUDINARY_API_SECRET
    // When doing a signed upload, you'll use a function like this:
    exports.handler = async event => {
      const file = event.body;
      const res = await cloudinary.uploader.upload(file, {
        image_metadata: true,
      return {
        statusCode: 200,
        body: JSON.stringify(res)
Code language: JavaScript (javascript)

In the code above, we import Cloudinary and dotenv. We configure Cloudinary and dotenv with the config function.

We’re also exporting the handler method, a typical synchronous serverless Lambda function that takes an event as a parameter. We’re getting the file from event.body and passing it to Cloudinary’s upload method.

In the return statement, we return the 200 status code and body as the response from Cloudinary.

Now let’s update the functionality for our frontend so that it works as expected. Update your App.js file with the following.

    import { useState } from 'react';
    import './App.css';
    function App() {
      const [loading, setLoading] = useState(false);
      const [success, setSuccess] = useState(false);
      const [imgUrl, setImgUrl] = useState([]);
      const readFile = (file) => {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = () => {
          reader.onerror = reject;
      const handleUpload = async (e) => {
        if( > 0) {
          const file = await readFile([0]);
          try {
            const response = await fetch(
                method: 'POST',
                body: file,
            const data = await response.json();
          catch (error) {
      return (
        <div className="App">
          <h4>Upload Images</h4>
          <input id="upload" type="file" onChange={handleUpload} hidden />
          <label className="uploadBtn" htmlFor="upload">{loading ? "Uploading..." : "Upload an Image"}</label>
          {success && <img className="imgUrl" src={imgUrl} alt="Uploaded new" />}
    export default App; 
Code language: JavaScript (javascript)

In the code above, we created state for the variables loading, success, and imageURL, which will help us keep track of when an image is uploading when it has already been uploaded and then get the URL for the uploaded image.

In the code above, we created states for the variables loading, success, and imageURL, which will help us keep track of when an image is uploading when it has already been uploaded and then get the URL for the uploaded image.

We have the readFile function, which is used to read a file and convert it to a blob URL in the format Cloudinary accepts.

We also created a function called handleUpload, and as its name suggests, it gets the file that needs to be uploaded and sends the API request to the serverless function we created. It returns a response with the image URL, which we then display after the image has been uploaded successfully.

Head over to your development server and upload an image. Here’s what mine looks like after a successful upload. Hopefully, you’re up and running as well.

In this article, we learned how to build an image upload feature using Netlify’s serverless functions and Cloudinary.

Here are some resources you might find helpful:

Back to top

Featured Post