Images play a significant role in the development of the internet. It’s a critical component of the web that improves a user’s experience, which can lead to an abysmal experience if unoptimized.
This article will utilize the Next/Image module shipped by Next.js to optimize rendered images. We’ll also add a custom loader
to improve the image optimization to add robust media transformations using Cloudinary.
Cloudinary offers a media management solution to manage, optimize, transform, and deliver visual media.
This project is completed on CodeSandbox, and you can fork it to get started quickly.
You can also find the source code on GitHub.
To follow the steps in this article, you should have:
- Adequate knowledge of JavaScript and React.js.
- The latest version of Node.js installed.
- A terminal such as ITerm2(MacOS) or Git bash (Windows).
- A Cloudinary account. You can create one here for free.
After successfully creating an account, Cloudinary will redirect us to our account’s dashboard, where we’ll see account details that will be useful later, including:
- Cloud name
- API Key
- API Secret
NOTE: Don’t share your Cloudindary credentials with anyone.
We’ll create a Next.js app in a new folder called custom-loader-app
by running the following command in our terminal:
npx create-next-app custom-loader-app
Next, we’ll navigate to the project directory.
cd custom-loader-app
Then, we’ll install the Cloudinary React SDK and Lodash.
npm install cloudinary-react
npm install lodash
Running npm run dev
starts a local development environment.
Next.js provides the next/image module, a wrapper of the HTML Img element. Next/image bakes in various performance optimizations, improving the core web vitals of pages using it. Next/image supports both local and hosted images.
In our project’s pages/components directory, we’ll create a file called NextImage.js with the following content:
import React from "react";
import Image from "next/image";
import styles from "/styles/Home.module.css";
const NextImage = () => {
return (
<div className={styles.imagecontainer}>
<Image
className={styles.image}
src="/small-dog.jpg"
alt="Food"
width={450}
height={280}
/>
<h1 className={styles.nextcard}>Next Image</h1>
</div>
);
};
export default NextImage;
Here, we’ve imported the next/image and rendered a local image. This image file with the title small-dog.jpg is in the project’s public directory.
Next, we’ll import and render the NextImage
component into the home page on pages/index.js by replacing the existing content with:
import Nextimage from "./components/NextImage";
import styles from "../styles/Home.module.css";
export default function Home() {
return (
<div className={styles.container}>
<h1>Image Optimization</h1>
<main className={styles.main}>
<Nextimage />
</main>
</div>
);
}
Next/image allows the specification of a loader, which appends a domain URL to a local image, thereby serving the image from a content delivery network (CDN) and providing other optimization capabilities.
We’ll require an Image component utilizing a loader. To do this, we’ll create a file in pages/components/
titled CloudinaryImage
with the following content:
import React from "react";
import styles from "/styles/Home.module.css";
import Image from "next/image";
const CloudinaryImage = () => {
const cloudinaryImageLoader = ({ src }) => {
return `https://res.cloudinary.com/ugwutotheeshoes/image/upload/bo_10px_solid_rgb:f78585,e_blur:290,b_rgb:e1e6e9,c_scale,r_10,h_280,w_450/v1632752254/${src}`;
};
return (
<div className={styles.nextcard}>
<Image
loader={cloudinaryImageLoader}
src="eatery/item-8.jpg"
alt="Food"
width={450}
height={280}
/>
<h1>Cloudinary Image</h1>
</div>
);
};
export default CloudinaryImage;
We’ve specified a custom loader in the next/image Image component using Cloudinary. The loader defines a border, blur, crop, height, width, and radius applied as transformations.
Alternatively, we could specify the Cloudinary as a loader in next.config.js
by updating the file to:
module.exports = {
images: {
loader: 'cloudinary',
path: 'https://res.cloudinary.com/ugwutotheeshoes/image/upload/',
},
}
Lastly, we’ll add the created CloudinaryImage
component to our home page, updating the pages/index.js
file to:
import Nextimage from "./components/NextImage";
import Cloudinary from "./components/CloudinaryImage";
import styles from "../styles/Home.module.css";
export default function Home() {
return (
<div className={styles.container}>
<h1>Image Optimization</h1>
<main className={styles.main}>
<Nextimage />
<Cloudinary />
</main>
</div>
);
}
The resulting image URL with a loader is: https://res.cloudinary.com/ugwutotheeshoes/image/upload/bo_10px_solid_rgb:f78585,e_blur:290,b_rgb:e1e6e9,c_scale,r_10,h_280,w_450/v1632752254/eatery/item-8.jpg
Here’s what the home page should look like now serving two images: one without a loader and the other with a loader.
In this post we discussed how to optimize images in Next.js apps using next/image. We also saw how to utilize custom loaders like Cloudinary to further enhance the delivery image.
You may be interested in reading the following documentation: