How to Optimize Images on Netlify with the Cloudinary Build Plugin

What's Inside 🧐

Netlify makes building and deploying Jamstack apps super easy, but without additional tools, your images are going to get deployed “as is”, leaving lots of potential room for saving precious bytes. Instead, we can use the Cloudinary Netlify Plugin and get automatic optimization and modern formatting to make sure we’re delivering as great and lean of an experience as we can.

What is Netlify?

Netlify is a hosting and automation platform that gives developers an easy way to build projects and deploy them to the web. It has a variety of features on top of that including serverless functions and forms, but we’re going to primarily look at simply deploying an app to the web.

What is a Netlify Build Plugin?

During the build and deploy process, Netlify provides hooks at different stages, allowing not only Netlify to add functionality to the process, but for developers to hook in with plugins.

For instance, if you wanted to run some set of functionality after the build completes on the output (like HTML, CSS, JS), we can run a build plugin “post-build”.

This is exactly how the Cloudinary Build Plugin works, which allows you to not only serve all your images from Cloudinary, but transform your images as well.

Why would we want to transform and serve our images with Cloudinary?

While Netlify will certainly serve your assets from a wonderful CDN, Cloudinary is able to provide additional benefits on top of serving from a CDN, including things like auto-optimization along with automatically serving the image with modern formats (like WebP, AVIF) if the browser requesting the image supports it.

This is a big deal, where typically this process is manual or cumbersome or it doesn’t even happen at all. Optimizing images and how we serve them help avoid long page loads for mobile users or those with slow internet connections and potentially eating up limited bandwidth.

What are we going to build?

So to test this out, we’re going to see how we can set up the Cloudinary Build Plugin on a deploy Netlify site.

To do this, we’re going to first deploy a simple web app example to Netlify as our base project.

Then, we’ll learn how we can use Cloudinary and install the Build Plugin to automatically optimize our images!

In order to follow along you’ll need a free Cloudinary and a Netlify account.

Disclaimer: I work for Cloudinary as a Developer Experience Engineer.

Step 0: Creating a new Next.js app from a demo starter

We’re going to start off with a new Next.js app using a simple image gallery of character posters from the TV series Arcane.

Inside of your terminal, run:

yarn create next-app my-arcane-wiki -e
# or 
npx create-next-app my-arcane-wiki -e

Note: feel free to use a different value than my-arcane-wiki as your project name!

Once installation has finished, you can navigate to that directory and start up your development server:

cd my-arcane-wiki

yarn dev
# or
npm run dev

And once loaded, you should now be able to open up your new app at http://localhost:3000!

New app in browser showing gallery of Arcane posters
New Arcane wiki app

Now what we’ll be focusing on in this application are the images. Specifically, we have our logo image along with a gallery of character posters.

Those are being served locally from the application and as we’ll see in Step 1, when deployed to Netlify, Netlify will serve those images from their own CDN.

We’ll later see how we can automatically optimize those images with Cloudinary!

Step 1: Deploying an application to Netlify

We have a few options to deploy our application to Netlify.

In this walkthrough, we’ll start from our application hosted in GitHub, but Netlify supports other Git providers as well as the ability to deploy locally via the CLI.

So starting off for this walkthrough, we’ll need our application hosted in GitHub. If you’re not familiar with this process, you can head over to the GitHub docs and learn how to add an existing project to GitHub using the command line.

Once your project is on Netlify though, we can get started by clicking the New site from Git button inside of our Netlify dashboard.

Netlify dashboard with highlighted button to create a new site from Git
Creating a new site in Netlify

On the next page, you’ll be asked to select your Git provider in order to import a project. Again, I’m using GitHub so if you’re following along, you can go ahead and select GitHub, otherwise select your Git provider of choice.

When doing so if you haven’t already, you’ll be asked to authenticate your account with Netlify, which gives Netlify the ability to grab your project as well as provide additional capabilities such as monitoring pull requests for creating automatic deployments.

But once authenticated, you’ll be asked to select your repository from Git!

Netlify new project wizard showing search of GitHub repository
Importing a project from GitHub

Select your repository and next we’ll see a configuration page.

One of the cool things about Netlify is it has the ability to automatically detect what kind of project you have. Because we have a Next.js project, Netlify sees that, and subsequently will install the Essential Next.js Build Plugin as well as specify the Build Command and Publish Directory for us.

Netlify project creation wizard showing build settings
Netlify build settings

So at this point, we can simply click Deploy site at the bottom and watch our project kick off!

On the next page, we’ll see that Netlify will give us a randomly generated site name and we’ll additionally see our new build in progress.

Once that’s complete, you’ll be able to open your new site and see it deployed to the web.

Netlify site dashboard showing successful deployment
New site deployed to Netlify

Now before we move on, if we open up the Network tab when visiting our site and look at the images, we can see that they’re all being served directly from Netlify.

Chrome showing Network tab with image requests from deployed Netlify site
Image requests in Network tab

If our images are already optimized, we might be fine simply serving them “as is”. But if they’re not, we’re sending images and wasting people’s bandwidth.

On top of that, we’re still serving them as JPEG files, which again is fine, but we can do better, which is where Cloudinary comes in!

Step 2: Installing and configuring the Cloudinary Build Plugin for Netlify

At the time of writing this article, the Cloudinary Build Plugin isn’t available quite yet to install right from the Netlify UI, so that means we’ll need to install it locally in our project using a Netlify configuration file and installing it as a package with npm.

Let’s start off by installing the package.

In your terminal, run:

yarn add netlify-plugin-cloudinary
# or
npm install netlify-plugin-cloudinary

Next, we want to set up our new Netlify configuration file.

Note: if you’re using your own project and already have your configuration file, you can simply add it to your existing one!

In the root of your project, create a new file netlify.toml and add:

  package = "netlify-plugin-cloudinary"

  cloudName = "[Your Cloud Name]"

Here we’re telling Netlify that we want to use the Cloudinary Build Plugin. We’re also specifying an input, particularly our Cloudinary Cloud Name, which we can get right inside our Cloudinary account.

To find your Cloud Name, head over to Cloudinary, log in, and at the top of the dashboard, you should be able to see and copy your Cloud Name.

Cloudinary dashboard showing highlighted Cloud Name
Finding your Cloudinary Cloud Name

Note: make sure to use your own Cloud Name and not mine, as that account is limited and might not work. You can get your own free account over at

Once you configured your Netlify config, go ahead and commit that file and push it out to GitHub or your Git provider.

Another cool thing about Netlify is as soon as you make a change on your main branch, by default, Netlify will kick off a new deploy, meaning we don’t need to do anything and can sit back and watch it work!

After the build finishes, we can now preview our site again, and we can see that our images are being sourced from Cloudinary.

Chrome dev tools inspector showing image sourced from Cloudinary
Image source coming from Cloudinary

Better yet, if we look again at the Network tab, we can see that our images are now being served as AVIF because Chrome supports that format along with smaller sizes!

Chrome showing Network tab with image requests from Cloudinary optimized and AVIF format
Optimized image requests in Network tab

Follow along with the commit!

Step 3: Updating plugin configuration to upload images to Cloudinary

By default, the Cloudinary Build Plugin for Netlify will “fetch” the images from remote locations, including Netlify, and serve it cached and optimized in front.

Alternatively, we can tell Netlify to upload all of those images to Cloudinary, and serve them directly from Cloudinary.

This gives us a few benefits, such as being able to have more control over how we transform our images and how they’re managed.

The best part, setting up our images to be uploaded instead of fetched is a simple config change away!

To do this we have two options: unsigned uploads by providing a Cloudinary Upload Preset or signed uploads by providing our API Key and API Secret.

We’ll walk through adding our API Key and API Secret to maximize our ability to control our images.

Note: if you want to learn how to create an Upload Preset to use unsigned uploads, check out my previous tutorial How to Programmatically Upload Images to Cloudinary in React & Next.js.

To start, we need to add a new input to our Netlify config.

Inside of your netlify.toml add a deliveryMethod of upload so that your config looks like the following:

  package = "netlify-plugin-cloudinary"

  cloudName = "[Your Cloudinary Cloud Name]"
  deliveryType = "upload"

Now before you push that up to Git, we have one more step we need to do.

Tip: if you already pushed this up, you can always start a new deployment from the Netlify UI after completing the below.

Next, we want to find our API Key and API Secret, which we’ll set as environment variables inside of Netlify.

You can find your Cloudinary API Key and API Secret in the same place we found our Cloudinary Cloud Name.

Cloudinary dashboard showing API Key and API Secret
Finding API Key and API Secret in Cloudinary

We’ll now copy these values over to Netlify.

Inside of Netlify, head over to Site Settings, Build & deploy, and then select Environment where at the top of the Environment section your should see Environment variables.

Here click Edit variables and we’ll want to add two variables with their corresponding values:

Netlify Environment settings showing added environment variables
Adding environment variables in Netlify

Finally, push your local netlify.toml changes up to Git, which should trigger another new Netlify deploy.

Once complete, we can now see that our images are specifying a delivery type of fetch.

Chrome devtools Network tab showing highlighted upload delivery method
Cloudinary images with upload delivery type

We can also now see that inside of our Cloudinary Media Manager, our images were uploaded to our account!

Cloudinary Media Manager showing Arcane image uploads from Netlify deploy
Arcane images in Cloudinary media manager

Follow along with the commit!

What else can we do?

Add Cloudinary images to your app with transformations

If you want to dig in and start using Cloudinary closer to your app, you can add a ton of additional features that work on the fly such as automatically cropping images to faces with face detection.

Learn how to apply transformations to create a thumbnail gallery.

Programmatically upload from a form

Running a website where visitors can sign up and log in often comes with the ability to upload an avatar or upload an image of some sort. We can use a simple form, collect the image with FormData, and upload it straight to Cloudinary with the API.

Learn how to upload images from a form in React and Next.js.