The image element of Next.js, next/image, is a developed form of the existing HTML element <img>, also known as an image tag, advanced for modern web architecture. It comes with a bunch of performance optimizations to assist you in achieving good Core Web Vitals. There are three core web vitals to learn about:
This looks at the loading execution of your web page. LCP diagnoses the time it takes to induce the largest component on the web page visible in the viewport. This can be a huge content block, video, or picture that takes up the essential real request on the page. This is a different thing than First Contentful Paint (FCP) which diagnoses the time starting from when the web page starts to load to when the very first component is reflected on the screen.
After the whole DOM is rendered, the biggest component on the webpage may alter. LCP does not stop counting, to the time when the biggest component or image is rendered on screen.
This is the discernment of the experience of the client while connecting with a website. Imagine you are clicking inside of a box rendered within a webpage and nothing happens. This dissatisfaction with the responsiveness and interactivity with the input occurs due to long input delays. FID needs real-time data and can’t be tested in the lab, like Google Lighthouse, whereas Total Blocking Time (TBT) can be measured in the lab and will grab the issues immediately which affect the responsiveness of the page and make it less interactive.
This could be a degree of overall layout stability of a website. A web page that suddenly shifts layout as it loads can lead to coincidental distraction and error. CLS happens when components have been moved after being first rendered by the DOM, or in the case of a button being rendered on the web page after the block of text, causing the block to move. A combination of distance shifted and its impact on the web page is acknowledged while calculating CLS.
A few of the pre-builtin optimizations in the next/image component are as follows-
Enhanced Performance - Using modern formats for images it always delivers accurately sized images for every aspect ratio and device.
Visually Stable - Avoids CLS by itself.
Faster Web Page Rendering - Images will load only when a user enters the viewport before there are blurred placeholders indicating loading in case of slow internet connections.
Flexible Assets - Without storing all-size images on the server, it provides dynamic image resizing whenever you need it.
To embed an image component in your application, first, you have to import the next/image component-
import Image from 'next/image';
Now you can assign the local or remote address of your image to the src attribute**.** Suppose we have to import the nature.jpg image file located in my public/assets directory. The following line will be written along with import statements in order to import that image. Basically, we are picking up its address by that import-
import naturePicture from '../public/assets/nature.jpg';
Importing images dynamically using require() and await import() aren’t supported here. The import statement must be static in order to be analyzed at the time of build.
One of the special things about using Next.js is that it can determine the width and height of your imported image automatically to avoid Cumulative Layout Shift (CLS) while the image is loading.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Image from 'next/image'
import naturePicture from '../public/assets/nature.jpg'
export default function HomePage() {
return (
<>
<h1>Nature Gallery</h1>
<Image
src={naturePicture}
alt="Picture of the nature"
// width={500} AUTOMATICALLY ASSIGNED
// height={500} AUTOMATICALLY ASSIGNED
// blurDataURL="data:..." AUTOMATICALLY ASSIGNED
// placeholder="blur" // BLUR WHILE LOADING (OPTIONAL)
/>
</>
)
}
The result will look like this…
If you want to use remote images instead of images stored locally, you have to pass the image URL directly in the src prop of an image component. This URL can be absolute or relative, but in that case, you have to provide props like optional blur, height, and width manually because Next.js doesn’t have access to remote files during its build process.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import Image from 'next/image'
export default function HomePage() {
return (
<>
<h1>Nature Gallery</h1>
<Image
src="https://cdn.relaxation.com/images/nature.jpg"
alt="Picture of the nature"
width={500}
height={500}
placeholder="blur" //OPTIONAL
/>
</>
)
}
If you want to access remote images by using the built-in Image Optimization API of Next.js then you have to pass the absolute URL of that image in src prop and then Next.js loader handles it internally.
src="/images/nature.jpg"
Create an entry of image and under this specify your domain in the next.config.js file.
1 2 3 4 5
module.exports = { Image: { domains: ['cdn.relaxation.com'], } }
Priority of Image Component
The very special and unique property of the next/image component of Next.js is that you can set the priority flag of the image. To do so you have to pass priority prop to the image component. After that, Next.js prioritizes it, especially while loading. If you do not specify it then by default it’s false.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
< Image
src = "/images/nature.jpg"
alt = "Picture of the nature"
width = {
500
}
height = {
500
}
placeholder = "blur"
priority //NOW, priority = true
/
>
You can style it as simply as you do with the element of HTML. Now that you have a good grip on the next/image component of Next.js we will move on to the advanced part of the image component.
This property is used to show an effect in place of an image while the image is loading, just like a placeholder in an input box which indicates the direction of how to fill the data when initially when there is no data in the input box. A blank space in place of an unloaded image can look weird. This can be easily seen in slow network connections; blur and empty are two possible values of that property where the default value is empty.
Blur itself contains two properties, blur, and blurDataURL. The blur property simply blurs the image data before it’s fully loaded (check the demo here), whereas the blurDataURL property provides you two effects instead of a simple blur, the Shimmer Effect (check the demo here) and Color Effect (check the demo here).
Note- The demos above are best experienced in slow network connections. Don’t worry, you don’t have to find slow internet, you can use network throttle provided by the developer tools of every browser to simulate a poor network. Set that throttle to slow 3G connection or you can make it slower by using custom profiles. Go to the link above to learn more about it.
If the object value in src prop contains the image imported statically, the image extension could be in any format available like JPG, WEBP, AVIF, or PNG. In the case of a blur, blurDataURL is opted by Next.js by default. But, if you dynamically import the image from any source and pass it to src prop, then you have to define the blurDataURL property manually. And in the case of it being empty, there is nothing, just a blank space.
In some circumstances, you could require more complex functionality. The advanced characteristics listed below are available as options for the <Image /> component.
All these properties are passed as props we are used to generally in React components.
Before the image passed in src prop loads properly, a DataURL is used as a placeholder, but it only comes into action when the placeholder is assigned a “blur” value. A base64-encoded picture is required because the image will be magnified and blurred; a small image (size less than 10px) is advised. Using larger images as placeholders may degrade the performance of your application. Also, you can use a solid color data URL to match the image by generating it manually, here is the link to generate it – https://png-pixel.com/.
1
2
3
4
5
6
7
8
9
10
11
type ImageType = {
type: 'element';
tagName: 'img';
props: {
//image is dynamically imported
src: "https://cdn.relaxation.com/images/nature.jpg";
width: 500
height: 500
placeholder: 'blur';
};
};
To use the properties of our image, we cast the type above. Now as we learned above we just have to pass props to our image component.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<Image {...ImageType.props} blurDataURL={getBase64(ImageType.props.src)} /> //definition of getBase64 function is given below //function to get base64 encoded image getBase64(image) { //As image is external we have to fetch first const imageRes = await fetch(image); // Convert the HTTP result into a buffer const arrayBuffer = await imageRes.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); return buffer.base64; }
The bounding box used to identify the intersection of the viewport with the picture and activate lazy loading is a string with similar syntax as the margin property with the default value of “200px”. Here is the link to learn more about it.
<Image {...props} lazyBoundary="300px"/>
Note- props mentioned here are the same as we explained about ImageType.props above, we are just spreading it here to avoid lengthy code.
If this is true, the source picture will be provided in its original quality, size, and format. The default value is false.
<Image {...props} unoptimized = true | false/>
When using layout=“fill”, this prop specifies how the picture (that you passed in src prop) will fit into its parent container. Basically, the value you pass here is assigned to the object-fit CSS property of the image. Possible values are cover, contain, fill, and none.
<Image {...props} objectFit="contain | cover | fill | none"/>
When using layout=“fill”, this prop specifies how the picture is positioned within its parent element. Basically, the value you pass here is assigned to the object-position CSS property of the image. Possible values are top, bottom, right, left, center, or any measuring value in px.
<Image {...props} objectPosition="top | down | bottom | center | 200px"/>
Once the picture has fully loaded and the placeholder has been deleted, this callback function is called. This function takes an object with the below-given properties as a parameter -
1 2 3 4 5 6
<Image {...props} onLoadingComplete={(obj)=> handleChange(obj)} /> obj = { naturalWidth: "500px", naturalHeight: "500px", }
This prop specifies the loading behavior of the image. Basically, there are two types of loading: lazy and eager. Lazy is the default mode for loading in which the image is loading until the time it is estimated to be a certain distance from the viewport, whereas eager mode loads the image immediately. Here is the link to learn more about it.
<Image {...props} loading="lazy | eager"/>
Note – eager mode is only used when you do it for a specific purpose because it generally disturbs the performance, in the case of early loading, use priority prop instead.
On-demand, pictures are dynamically optimized and saved in the <distDirectory> /cache/images directory. Until the expiration date, the optimized image file will be provided for subsequent requests. When a request is received that matches a cached but expired file, the cached file is removed before a new optimized picture is generated and cached. Either the minimumCacheTTL setting or the upstream server’s cache-control header, whichever is bigger, determines the expiry (or rather max-age). The cache-control header’s max-age value is utilized specifically. When both s-maxage and max-age are found, s-maxage is chosen.
When the upstream image does not include a cache-control header or the value is very low, you can use minimumCacheTTL to boost the cache time.
You can decrease the total number of potential produced pictures by configuring deviceSizes and imageSizes.
You can deactivate numerous picture formats in favor of a single image format by configuring formats.
For cached optimized pictures, you may set the Time to Live (TTL) in seconds. In many circumstances, it’s preferable to utilize a static picture import, which will hash the file contents and store the image indefinitely with an immutable cache-control header.
1
2
3
4
5
6
//next.config.js
module.exports = {
Image: {
minimumCacheTTL: 50, //In seconds
},
}
You may import static files using the default behavior, such as
import image from ‘./image.jpg’ and then send it to the src prop. If this functionality clashes with other plugins that require the import to perform differently, you may choose to disable it.
1 2 3 4 5 6
//next.config.js module.exports = { Image: { disableStaticImages: true }, }
Now that you’ve learned about image components, their props and how to use them, you can solve complex problems in a simple way by just passing value to the props.