How does NextJS Image work? How do I optimize my Nextjs build? Lazy Loading Images? - Right article to find out :) ยท NextJS is fast becoming my favorite...

NextJS is fast becoming my favorite frontend framework because of the endless advantages over a basic React application, one of those said benefits would be the Built-in Image Component.
In this article, we would take a look at the Image component from NextJS and learn how to use it to optimize an image in our web app.
By the end of this article, you should understand the following concepts:
next/imagenext.config.js< img /> tag in NextJSOrdinarily, if you were going to make use of an image in your website/app you would do this ( assuming the image is in the same directory as the webpage it is accessing ):
<img src="./apple.jpg">
You can go further by adding an alternative text (for screen readers or when the image cannot be loaded) by doing this:
<img src='./apple.jpg' alt='Image of an apple' />
However, this format doesn't solve image optimization aspects like image size, web formats, and responsiveness with this single usage.
NextJS offers automatic image optimization which solves all of the above as well as common tasks like internalization and routing.
The golden rule for any performance optimization simply put is giving users what they want in the shortest possible time or providing a fall-back if need be.
Hence NextJS provides us with a built-in image optimization API, next/image, a canonical form for native automatic image optimization.
next/imageThe Image component in NextJS is quite similar to the native html <img>, it's an extension of this element and can be used by importing it from next/image and using it like you'd use a component with props.
import Image from 'next/image';export default function SampleImage({ source }) {return (<div><Image src={source} alt='Image alt text' /></div>);}
The Image tag has a couple of props available to it for use asides the src and alt prop, we'd take a look at some of them
width and height propimport Image from 'next/image';export default function SampleImage({ source }) {return (<div><Image src={source} alt='Image alt text' height={400} width={400} /></div>);}
layout proplayout="fill". This will stretch the image to the width and the height of the parent element. When using the layout="fill" prop, it is often best to pair it with objectFit="cover". This will allow the image to maintain its aspect ratio while filling the elementโs entire content box.
To achieve this, wrap the Image component as a child of a <div> element. Then add a width and height to the parent <div> element, along with giving it a position="relative".import Image from 'next/image';export default function SampleImage({ source }) {const myStyle = {height: '400px',width: '400px',position: 'relative',};return (<div style={myStyle}><Image src={source} alt='Image alt text' layout='fill' objectFit='cover' /></div>);}
This way, we can see that the image is taking up the 400-pixel square that we wanted, but the aspect ratio of the image is still in place. The parts of the image that do not fit within the parent element are clipped.
Other layout values are intrinsic, fixed, and responsive.
loader propsrc, width, quality). Setting the loader as a prop on the Image component overrides the default loader defined in the images section of next.config.js.import Image from 'next/image';const sampleLoader = ({ src, width, quality }) => {return `https://example.com/${src}?w=${width}&q=${quality || 75}`;};const MyImage = (props) => {return <Image loader={sampleLoader} src='me.png' alt='My Picture' width={500} height={500} />;};
sizes propimages.imageSizes property in your next.config.js file. These widths are concatenated with the array of device sizes to form the full array of sizes used to generate image srcsets.module.exports = {images: {imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],},};
Or by defining it in your component like,
<Image src={src} alt='image-alt-text' sizes='320 640 700' layout='responsive' />
Keep in mind that it is recommended to define sizes only when using a responsive or fill layout.
quality prop1 and 100 where 100 is the best quality. Defaults to 75.<Image src={src} alt='image-alt-text' quality={100} layout='fill' />
priority propfalse. When true, the image is considered high-priority and preloaded.
You should use the priority property on any image detected as the Largest Contentful Paint (LCP) element.
Should only be used when the image is visible above the fold. Defaults to false.<Image src={src} alt='image-alt-text' width={500} height={300} priority />
placeholder propplaceholder property is used as a fallback image when an image is loading. Its possible values are blur or empty.
When empty, there will be no placeholder while the image is loading, only empty space. When blur, the blurDataURL property will be used as the placeholder. If src is an object from a static import and the imported image is .jpg, .png, .webp, or .avif, then blurDataURL will be automatically populated.<Image src={src} alt='image-alt-text' width={500} height={300} placeholder='blur' />
blurDataURL propblurDataURL prop is a placeholder image that loads before the src image successfully loads and must be a base64-encoded data URL image that is effectual only when used in combination with placeholder=โblurโ.<Imagesrc={src}alt="image-alt-text"width={600}height={450}placeholder="blur"blurDataURL=โdata:image/png;base64,[IMAGE_CODE_FROM_PNG_PIXEL]โ/>
objectFit propobjectFit prop defines how the image will fit into the container of it's parent, quite similar to the object-fit CSS property. It is used with layout=fill or an image with a set width and height.<Image src={src} alt='image-alt-text' layout='fill' objectFit='contain' />
It has a possible value of: contain, cover, fill, none, and scale-down.
unoptimized proptrue, the source image will be served as-is instead of changing quality, size, or format. Defaults to false.<Image src={src} alt='image-alt-text' width={700} height={450} unoptimized />
next.config.jsYou can configure your NextJS image through the next.config.js file
domainsdomains in next.config.jsmodule.exports = {images: {domains: ['example.com'],},};
loadermodule.exports = {images: {loader: 'cloudinary',path: 'https://your-site.com/assets/images/',},};
Keep in mind that when loader is set to an external image service, the domains config is ignored.
For more advanced cases of props in NextJS, there are other props that you can add to the Image component as well as configurations. Check out the full documentation here.
Image optimization in Next.js improves the user and developer experience but just like every other thing in programming, the Image component has some limitations one of which is its inability to adjust CSS directly. Unlike the native <img> element whereby you can pass a style prop to override its CSS. The NextJS image component doesn't support the style property at all. Hence to style the source image, name it with a className then target it with your CSS.
<Image src={src} alt='image-alt-text' width={700} height={450} className='myImage'></Image>
P.S: Next.js forces using their component instead of the native
tag by including the corresponding linter check to the app build process. So if you're going to make use of the
tag in a NextJS application you'd add the following to disable the check
// eslint-disable-next-line @next/next/no-img-element<img src={src} alt='myImg' className='myImage' />
Or by adding "@next/next/no-img-element": "off" in the .eslintrcconfig file.
I hope you enjoyed reading this as much as I enjoyed writing it and would be building your NextJS app as soon as possible.
Resources used:
๐๐พ Learn more about me
๐๐พ Connect on LinkedIn
๐๐พ Subscribe to my blog, let's feast
I'm Jide, a Full-Stack Software Engineer with penchant for Web/App development. I like scratching my own itch and writing about Web Technologies, UI/UX case studies, and Tech-bits thereof. During my spare time, I'm an autodidact polymath acquiring knowledge from various resources online.
ยฉ 2025 Jide Abdul-Qudus. All rights reserved.