Partners

Next.js images

What You Should Know about the Next.js Image component

Posted on October 19th, 2021 by Antonello Zanini

Next.js 10 introduced a built-in image component with automatic optimization capabilities, and this has been one of the most important features ever added to Next.js. This is because images take up 50% of the total bytes of web pages. So, they have a heavy impact on Largest Contentful Paint, which is one of the most important metrics Google uses when ranking a website. This is what drove Next.js to implement such a cool feature. In other words, treating Next.js images correctly is now vital.

Unfortunately, despite being part of Next.js since late October 2020, many developers have not adopted it yet. So, let’s learn everything you should know about the next/image component and image optimization.

Delving Into next/image

As stated in the official documentation, next/image offers everything required to deal with Next.js images as expected on the modern web. Specifically, it comes with an extension of the HTML <img> element, represented by a standalone <Image /> component. This was developed with the Core Web Vitals scores in mind, which are an important measurement of user experience and are factored into the Google search rankings

But thanks to the <Image> component, you do not have to worry about them. This is because it comes with several built-in performance optimizations to help you achieve high Core Web Vitals scores. Specifically, here is the list of the most important optimizations the <Image /> component include:

  • Faster page load: Next.js images will only be loaded when entering the viewport, being lazy-loaded by default.

  • Responsiveness: images will be resized according to the device used.

  • Visual stability: the cumulative layout shift problem is automatically avoided.

  • Improved performance: Next.js images can be resized and encoded on-demand, even when they are stored on remote servers or an external data source, such as CMS. This prevents you from having to create images with different sizes at build time, making it faster.

How To Use the Next.js Image Component

First, you must be sure that your version of Next.js is greater or equal to 10. This is the only prerequisite required. That assured, you will be able to import the <Image /> component as follows:

import Image from 'next/image'

Then, you must give a value to the props below:

  • src: it can be either a statically imported image file or a path string. In the latter case, if you want to use absolute external URLs, you must add their domains in the next.config.js file as shown here:

module.exports = {
images: {
domains: [
'external-domain-1.com',
'external-domain-2.com'
],
},
}

And this is how it works with a URL:

import Image from 'next/image'
import fooImage from '../public/assets/foo.jpg'
function FooComponent() {
return (
<>
{/*// ...*/}
<Image
src={profilePic}
alt="Foo image"
layout={"fill"}
// ...
/>
{/*// ...*/}
</>
)
}
  • width: an integer representing the width of the image in pixels. It is mandatory except for statically imported images or when using the fill layout property. 

  • height: an integer representing the height of the image in pixels. It is mandatory except for statically imported images or when using the fill layout property. 

Let’s see width and height in action through an example:

import Image from 'next/image'
import fooImage from '../public/assets/foo.jpg'
function FooComponent() {
return (
<>
{/*// ...*/}
<Image
src={profilePic}
alt="Foo image"
width={3840}
height={2160}
// ...
/>
{/*// ...*/}
</>
)
}


Keep in mind that the width and height props must match your image ratio dimensions.

As you can see, this is not much different from using the HTML <img> element. Let’s now dive into the differentiating features offered by the Next.js <Image /> component and accessible via optional props.

Layouts

The <Image /> component comes with a layout prop. At the time of writing, these are the four different layouts currently supported:

  • intrinsic: this is the behavior adopted by default. The image will be adjusted visually on smaller viewports and maintain the original dimensions for larger viewports. In other words, the height and width provided as props will act as the maximum dimensions for the image. Test it out here.

  • fixed: the image dimensions will not change as the viewport changes. There is no resizing or responsiveness, just as happens with the HTML <img> tag. In this case, the image can overflow the parent component. Test it out here.

  • responsive: the image will be scaled down for smaller viewports and scaled up for larger viewports. Make sure that the parent element containing the image uses the display: block CSS rule in its stylesheet. Test it out here.

  • fill: the image will scale both width and height to the dimensions of the parent element, provided that the latter has position: relative in its stylesheet. This layout tends to be used along with the objectFit and objectPosition properties. Also, when using this layout width and height do not have to match image dimensions. Test it out here.


Let's see how to use the layout props in the snippet below:

import Image from 'next/image'
function FooComponent() {
return (
<>
{/*// ...*/}
<Image
src={"https://external-domain-1.com/fooImage.jpg"}
alt="Foo image"
width={3840}
height={2160}
layout={"responsive"} // intrinsic|fixed|responsive|fill allowed
// ...
/>
{/*// ...*/}
</>
)
}


Now, let’s understand how resize optimization works through an example. Let’s say you have a large 3840x2160 image. When declaring a width of 3840/3 pixels and a height of 2160/3 pixels, the <Image> component will automatically resize the source file before serving it to the clients. Consequently, the clients will download the image at 1,280 pixels, not the original 3,840 pixels. Plus, the image file will be converted into a more compressed WebP file.

Then, when using the responsive and fill layouts, the server will take care to provide the client with the best possible file in terms of size according to the size of the device used. In other terms, Next automatically shrinks the image file based on how small a screen is. You can verify this by reaching the network tab of your browser dev tools while resizing the aforementioned demos in the responsive mode. What will happen is that each time a size breakpoint is hit, Next will provide the client with a new file with the right size. You can even customize these breakpoints as described here. Anyway, note that this behavior is not applied when using the intrinsic  or fixed layout. 

Next.js images features

These are the other most important properties supported by the Next.js <Image /> component:

  • loader: a function that will be called when resolving the image URL. If you give this value a prop, the default loader defined in the Next.js images section of next.config.js will be overridden.

  • sizes: a string providing information on how wide the image should be at different breakpoints. This is used when employing the responsive or fill layout as explained earlier. Learn more here.

  • quality: an integer between 1 and 100 representing the quality of the optimized image by the Next server. The default value is 75.

  • priority: a boolean to give the image high priority. If set to true, the lazy loading will be avoided and the image preloaded. This should be set to true when dealing with the Largest Contentful Paint element. The default value is false.

  • objectFit: it defines how the image will fit into its parent container when using the fill layout. Its value is passed to the object-fit CSS property.

  • objectPosition: it defines how the image is positioned within its parent element when using the fill layout. Its value is passed to the object-position CSS property.

  • onLoadingComplete: a callback function invoked when the image is completely loaded and the placeholder has been removed.

  • unoptimized: a boolean allowing you to disable any sort of optimization in terms of quality, size, or format and achieving something close to the default <img> behavior. The default value is false.

  • placeholder: the placeholder to use when the image is loading. Two values are supported: blur or empty. The default value is empty. If blur is set, the blurDataURL prop will be used as placeholder. For statically imported images, the blurDataURL field will be automatically populated. For dynamic images, you must define the blurDataURL property. If empty is set, empty space will be shown while loading the image. You can test the blur placeholder here. Note that this prop was introduced only in Next.js 11.

Benefits of the DatoCMS Image Management combined with Next.js Image

As you just learned, the officially supported next/image API is a powerful tool. However, it offers so many options that implementing the desired behavior can turn into a challenge. This is particularly true when you want to adopt cool placeholders when dealing with images coming from a CMS. Luckily for you, DatoCMS, Next.js CMS natively comes with the responsiveImage query. When used, this API will return pre-computed image attributes that will allow you to achieve responsiveness for your images effortlessly. 

To make things even easier, you can also download the react-datocms package. This exposes an <Image /> React component that supports the aforementioned props supported by the Next.js respective component, and that pairs with the responsiveImage query. Plus, the DatoCMS <Image/> component implements a special feature. When used in conjunction with the responsiveImage query, it automatically embeds low-quality image placeholders (LQIP) in base64 format directly on your page, with no additional requests required. 


This way, you can avoid the confusion generated by missing or inadequate placeholders used when the images are loaded lazily. See how fancy it looks:


Find out more about it here.

Conclusion - Next.js images

Here we looked at everything every Next.js developer should know about next/image, introduced to make image management easier.

This is because the modern web requires high standards when it comes to dealing with images, which usually represent the heaviest part of web pages. This is also why it is so important to know how to tackle all the common issues coming with images.

Thankfully, the Next.js image component is a ready-to-use, advanced, yet simple, tool. And learning everything required to master it is what this article was about. Yet, this component does not provide an easy solution to all problems related to image rendering. Specifically, using placeholders while images are loading can be tricky. But as we have seen, you can avoid this headache by adopting DatoCMS. 
Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on Twitter with any questions, comments, or suggestions.