Images play a significant role in the development of the internet. It is 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.
Sandbox
This project is completed on CodeSandbox, and you can fork it to get started quickly.
You can also find the source code on GitHub.
Prerequisites
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 - Create one here for free.
Setting up a Cloudinary account
After successfully creating an account, Cloudinary will redirect us to our account's dashboard, where we see account details that will be useful later on, including:
- Cloud name
- API Key
- API Secret
NOTE: Do not share your Cloudindary credentials with anyone.
Installing the project dependencies
We create a Next.js app in a new folder called custom-loader-app
by running the following command in our terminal:
1npx create-next-app custom-loader-app
Next, we’ll navigate into the project directory.
1cd custom-loader-app
We proceed to install the Cloudinary React SDK and Lodash.
1npm install cloudinary-react2 npm install lodash
Running npm run dev
starts a local development environment.
Adding a new local image with Next.js Image
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 create a file called NextImage.js with the following content.
1import React from "react";2 import Image from "next/image";3 import styles from "/styles/Home.module.css";4 const NextImage = () => {5 return (6 <div className={styles.imagecontainer}>7 <Image8 className={styles.image}9 src="/small-dog.jpg"10 alt="Food"11 width={450}12 height={280}13 />14 <h1 className={styles.nextcard}>Next Image</h1>15 </div>16 );17 };18 export default NextImage;
Here, we 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 import and render the NextImage
component into the home page on pages/index.js by replacing the existing content with:
1import Nextimage from "./components/NextImage";2 import styles from "../styles/Home.module.css";3 export default function Home() {4 return (5 <div className={styles.container}>6 <h1>Image Optimization</h1>7 <main className={styles.main}>8 <Nextimage />9 </main>10 </div>11 );12 }
Adding an image using Cloudinary as a custom loader
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 require an Image component utilizing a loader. To do this, we create a file in pages/components/
titled CloudinaryImage
with the following content:
1import React from "react";2 import styles from "/styles/Home.module.css";3 import Image from "next/image";4 const CloudinaryImage = () => {5 const cloudinaryImageLoader = ({ src }) => {6 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}`;7 };8 return (9 <div className={styles.nextcard}>10 <Image11 loader={cloudinaryImageLoader}12 src="eatery/item-8.jpg"13 alt="Food"14 width={450}15 height={280}16 />17 <h1>Cloudinary Image</h1>18 </div>19 );20 };21 export default CloudinaryImage;
We 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 doing updating the file to:
1module.exports = {2 images: {3 loader: 'cloudinary',4 path: 'https://res.cloudinary.com/ugwutotheeshoes/image/upload/',5 },6 }
Lastly, we add the created CloudinaryImage
component to our home page, updating the pages/index.js
file to:
1import Nextimage from "./components/NextImage";2import Cloudinary from "./components/CloudinaryImage";3import styles from "../styles/Home.module.css";4export default function Home() {5 return (6 <div className={styles.container}>7 <h1>Image Optimization</h1>8 <main className={styles.main}>9 <Nextimage />10 <Cloudinary />11 </main>12 </div>13 );14}
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.
Conclusion
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 enhance the delivery image further.
You may be interested in reading these: