Optimize images with Next.js and Cloudinary

Jia Yi

Jia Yi · 08 June 2021

3 min read

Next Js Image with Cloudinary

Next.js Image has some great features this includes lazy loading, placeholder and more. It even comes with the ability to work with other cloud providers through the loader option in next.config.

Cloudinary does have its SDK, but this comes at the cost of an external package.

If you are looking to use Cloudinary for transformations on your source images; You could pair it with Next Image to utilize the features provided while saving on bandwidth and improve performance through Cloudinary's image transformations.

There is one problem with this approach. The built-in loader limits the transformations; this means you must use c_limit rather than the image transformation of your choice.

Next Image Wrapper

We will be using a Next Image wrapper as a workaround for this problem.

myImage.js
import Image from 'next/image';

const myImage = ({
  sizes,
  src,
  alt,
  imgWidth,
  height = 512,
  transformation,
  ...rest
}) => {
  const myLoader = ({ src, width, quality }) => {
    const path = `upload/f_auto,q_auto,w_${
      imgWidth ? imgWidth : width
    },h_${height}${transformation ? ',' + transformation : ''}/`;
    return src.replace('upload/', path);
  };

  return (
    <Image sizes={sizes} loader={myLoader} src={src} alt={alt} {...rest} />
  );
};

export default myImage;
Note that...
This example uses Cloudinary absolute URL, adjust myLoader if you are using a relative path.
Sizes generate a list of images based on your imageSizes & deviceSizes which may or may not be something that you want. Adjust accordingly to your needs.
Using dynamic transformation also opens up the opportunity for bandwidth/transformation abuse. Do use your image provider restriction to allow required transformations only. Such as strict transformations by Cloudinary in this case.

Using your custom Image

import myImage from './myImage';

...

    <myImage
      imgWidth={50}
      height={50}
      src={avatar.url}
      alt={avatar.name}
      transformation={'c_thumb,g_face'}
      layout='fill'
      objectFit='cover'
    />

...

Using your myImage.js should be pretty straightforward, I will be passing an imgWidth and height of 50 for an avatar image (50 x 50). Along with the transformation of c_thumb,g_face provided by Cloudinary.

Bandwidth saved

Image Bandwidth Saved

Taking an example image from Cloudinary, the initial size is ~755kB while the delivered image is ~1.2kB! That is over 750kB (90%) saved from a single image.

In an application that has many user-uploaded images that is several MB, you can have a tremendous reduction in bandwidth costs and performance improvement.

Wrapping Up

Although this article uses Cloudinary as the cloud provider, you could apply the same principle to other image providers and utilize Next Image with the transformations provided by your image providers.

This article is also my first post so a big thank you for sticking to the end. Cheers 🥂 and till next time!

Resources