Netlify Developers

Compose Conference 2024 is coming!  Submit a talk

How to serve optimized images using Netlify's Image CDN

by Phil Hawksworth

Not only can Netlify’s Image CDN optimize image assets to improve site performance, but it can also handle common asset manipulation tasks on the fly. This cuts your site build times and powers valuable techniques such as responsive images and lazy loading.


Use a URL like this to serve your image through Netlify’s Image CDN:


This post explains how you can quickly start using the Netlify Image CDN, and demonstrates some helpful techniques to make using this service fit conveniently into your development workflow. Learn how to use a single image to provide all of the required asset sizes for responsive images using the example below.

An example responsive image

Resize your browser window to see the different image sizes being used in the srcset below.

Blue flowers

Using the tiny, small, medium, or large version of the full size original image.

(Image credit: TOMOKO UJ, Unsplash)

No setup required, just a URL

To begin using Netlify’s Image CDN, you don’t need to install or enable anything in your Netlify Admin. You simply need to make requests for your assets via a special URL pattern that Netlify recognizes:

Terminal window
# An image served from your site's files
# The same image, but served from Netlify's optimized Image CDN

You might recognize this special URL pattern from other tools you can use in your sites on Netlify, such as Netlify Functions. That /.netlify/ path is reserved on Netlify to access these sorts of helpers and utilities, so for those already using Netlify Functions this will already feel a little familiar.

Convenience and future-proofing

When using a service like this, I like to make it as unobtrusive in my code as possible. That way, should I ever wish to swap it out for an alternative, I can do so without a major refactor. Since the API is the URL, a small amount of abstraction using Netlify Redirects can help us achieve that.

Let’s create a convenient URL pattern we can use to serve the full-sized original image, but serve it from the Netlify Image CDN rather from our own site assets. A few lines in our netlify.toml file will do that for us:

# Requests to URLs matching this pattern...
from = "/images/full/:file"
# ...will resolve to this URL pattern
to = "/.netlify/images?url=/images/:file"
# ... and the status code of 200 will make this behave as a rewrite
status = 200

Other excellent Image CDN and optimization services out there like Cloudinary or Imgix also let you control their APIs through URLs. This means that should you need to upgrade to another service, perhaps to gain access to their more detailed asset manipulation features, you can do so by modifying the URL redirect rules here in your netlify.toml (after creating accounts with them, for example), and leave all of the image URLs across your site untouched.

With our redirect rule in place, a small change to the path used to source our images will let us choose to serve that image from the Image CDN.

From this:

<!-- an image served from my assets folder -->
<img src="/images/seedlings.jpg" alt="A photo of some green seedlings" />

to this:

<!-- an image served from my Netlify's Image CDN, originally sourced from my assets folder -->
<img src="/images/full/seedlings.jpg" alt="A photo of some green seedlings" />

Tip: Assets can be on your sites or third party domains

Netlify’s Image CDN needs to source and ingest your image asset before it can optimize, cache, and serve it, which is done by specifying the URL where this can be found. This might be within your site or an external domain. For security reasons, requests for assets on external domains require a little config, which we’ll get to later.

On-demand image resizing and manipulation

The Netlify Image CDN can also perform a number of image manipulation tasks for us. It’s very common to need differently sized versions of images for optimal display, as seen in our responsive image example above. Doing this for every single image in your site as part of each build can be computationally expensive and make builds take a long time. Handing this off to Netlify to do on-demand the first time an asset is requested in a given size and then caching that result can simplify and speed up our build process.

Including a width or height parameter in the URL will return a suitably resized image. Using just one or the other will retain the aspect ratio for us. Like this:







Tip: supported parameters

For information about all of the parameters we support for things like resizing, cropping, transforming image formats, and more, take a look at the Transform Images section of the Image CDN documentation

Utility URLs for resizing

Now let’s make these URLs more convenient and better abstracted on our site. Similar to the redirect rule we created for our full-sized images (/images/full/file-name.jpg), we could create some mappings for common sizes we might want so that the keywords small, medium, and large each map to a URL with given width parameters. We could also make a rule which lets us pass a width parameter dynamically, like this:

# Get a width and file name value from the URL
from = "/images/:width/:file"
# ...and pass them along as the correct request parameters
to = "/.netlify/images?url=/images/:file&width=:width"
status = 200

Order matters!

Watch out for an easy mistake here. Netlify treats the order that rules appear in the netlify.toml file as the order of priority, meaning that the first matching rule found is the one that will be applied. This is handy for creating logic in your rules.

To make our example work as we would like, we need to add the rule that catches the variable input for width after the rule that catches the word “full” in the same part of the URL as shown below:

# Serve a full size version
from = "/images/full/:file"
to = "/.netlify/images?url=/images/:file"
status = 200
# ...or serve a resized version
from = "/images/:width/:file"
to = "/.netlify/images?url=/images/:file&width=:width"
status = 200

Nice. Now we have some intuitive URLs we can use to serve our images in any size.







(or /images/full/blue-flowers.jpg)

Different asset sizes for responsive images

We’ve got everything we need to deliver the different asset sizes for use in our srcset in responsive images. A full explanation of how the responsive images work is available at MDN, but here’s a look the HTML:

/images/200/blue-flowers.jpg 200w,
/images/400/blue-flowers.jpg 400w,
/images/800/blue-flowers.jpg 800w,
/images/1200/blue-flowers.jpg 1200w
sizes="(max-width: 450px) 200px,
(max-width: 850px) 400px,
(max-width: 100px) 800px,
alt="Some blue flowers"

Lovely! We’re using readable, intuitive image URLs serving assets that are resized, optimized, and cached for us on demand. And should we decide to make changes to the size variant in our set of images we only need to edit a URL.

Depending on what tools you are using to build your sites, this can also be a useful place for another bit of abstraction. A partial or a component that generates this markup for you when you pass it a file name and an alt tag (don’t forget those alt tags, friends!) can keep your code nice and clear, and formalize some common conventions across your sites for how you deliver responsive images.

Using images from remote domains

The example here uses image assets which are part of the same site, so that relative paths are passed to Netlify’s Image CDN.

You can also feed the Image CDN assets from external domains. In order to prevent your site from becoming a gateway for anyone to perform unlimited image transformations on any assets, we give you control over which domains can be used. To do this, it’s time to add another bit of config to your netlify.toml file, where you can add an array of granted domains and use Reg Ex to describe detailed paths etc:

remote_images = ["*", "[bcr]at/.*"]

Assets on relative paths, sourced from your site gain all the benefits of our atomic deploys and their default cache behaviors, so assets on the Image CDN don’t become outdated as you deploy updates to your site. Assets on remote domains have different default cache characteristics. For information on how to control this, and other information about using remote domains with the Image CDN, take a look at the docs.

Bonus! Instant format optimization

You can specify the format you’d like to use to deliver your assets by providing a format (fm) parameter in the URL.

However, if you don’t specify a format, the Netlify Image CDN will determine the most efficient format for the browser requesting the image, and automatically return that using the following logic:

  1. Use avif if accepted
  2. Otherwise, use webp if accepted
  3. If neither is accepted, use the original format

Global infra in your local development

To get access to these capabilities while running your code in a local development environment, run your build using netlify dev which enables various Netlify Build and platform services locally, to smooth your development workflow.

Running your local build this way will provide handlers to those special /.netlify/ URLs, including automatically replicating the image transformation behaviour so that you can review appropriately as you build.

The netlify dev command is made available by installing the Netlify CLI and will serve your sites locally in a way that provides access to Netlify Functions, Edge Functions, Redirects, Image CDN and more.

Terminal window
# Install Netlify CLI
npm i -g netlify-cli
# Run your build with additional Netlify utilities
netlify dev

Try it on one of your sites today!

More resources for handling images