next/imageA picture is worth a thousand words, and images are an important part of the web to communicate with users. Defining them in their most basic form is straightforward and done with the humble <img> element:
<img src="image.jpg">

Ordinarily, the sourced image, image.jpg, is embedded into a web page, assuming the image is in the same directory as the HTML page.
You can — and you should — go further in this canonical form of image definition by adding an alternative text (alt) that describes an image if a browser or screen readers can’t load it:
<img src="image.jpg alt="describe the image here"/>
But with images on the web, the devil is in the detail. As the web evolved, so did the need for image optimization, whether it be for user or developer experiences.
To ensure users are served the most optimal image available, aspects like image size, web formats, and responsiveness must be addressed.
Solving for the user’s need is doable through the img element’s plethora of APIs for optimization. However, they can quickly become unwieldy to unpack. This is where automatic image optimization can benefit developers.
Frameworks like Next.js offer an abstraction that solves the most common, mundane, and complex tasks like routing, internalization, and image optimization.
According to the Next.js team, the goal with Next.js is to improve two things: developer and user experiences. And while most of the optimization focuses on reducing the amount of JavaScript shipped to users, there are other aspects like images that need optimization as well. Enter Next.js 10.
Next.js 10 welcomed a built-in image optimization API, next/image, as a canonical form for native automatic image optimization, providing five benefits.
With optimized images that are loaded lazily by default, users can expect a performance boost in website load time, ultimately improving the overall user experience.
With next/image’s simple-to-use API, developers have an improved experience themselves with the ability to define a basic image, tweak it to their heart’s content, or delve into advanced configuration options like caching and loaders.
Build times aren’t increased as a side-effect of optimization because Next.js optimizes images on-demand as users request them, instead of at build-time.
Images are lazy-loaded by default and can be served in modern formats like WebP in supported browsers.
Next.js can also automatically adopt future image formats and serve them to browsers that support those formats.
next/image APIThe next/image API is the sweet spot of image optimization in Next.js. It exposes an <Image/> component as a conventional single-source of truth. This means you only need to learn how to use one API to handle image optimization in Next.js.
By design, and in its most basic form, the <image/> component is fundamentally similar to the HTML img element because they both accept a src and alt attribute/property:
// 1. Import the `Image` component from the `next/image` API
import Image from 'next/image';
export default function CardImage({imageSrc, imageAltText}) {
return (
<div classname="cardImageWrapper">
{/* 2. Use the `Image` component as you would any other component */}
<Image src={imageSrc} alt={imageAltText}/>
</div>
)
}
The functionality of the <Image/> component can extend with a number of props available in it. Let’s take a look at them.
src propThe src is the single source of truth for the <Image/> component:
<Image src="image.webp"/>
To use the image src, it must be one of the following:
next.config.jsIn this case, we’ll import a static image file:
import Image from 'next/image';
// Import a static image file
import defaultCardImage from '../public/defaultCardImage.webp';
export default function CardImage({imageSrc = defaultCardImage, imageAltText}) {
return (
<div classname="cardImageWrapper">
<Image src={imageSrc} alt={imageAltText}/>
</div>
)
}
width and height propsThe absolute width of an image is in pixels. This is required except for statically imported images or images with the layout prop set to fill:
<Image
src="image-src"
alt="image-alt-text"
width={40}
height={40}
/>
loader proploader is a custom function that resolves URLs. Given the src , width , and quality parameters, it returns a URL string:
import Image from 'next/image'
// You can add as many loader as you want, and use them conditionally.
// See https://nextjs.org/docs/basic-features/image-optimization#loader
const sanityIoImageLoader = ({ src, width, quality }) => {
return `https://cdn.sanity.io/${src}?w=${width}&q=${quality || 75}`
}
function CardImage() {
return (
<Image
loader={sanityIoImageLoader}
src="image-src"
alt="image-alt-text"
width={500}
height={500}
/>
)
}
sizes propThe sizes prop is akin to the HTML img element sizes attribute. With that, sizes are set to indicate a set of source sizes as described in the MDN docs:
<img src="image-src" alt="image-alt-text" srcset="(max-height: 500px) 1000px"/>
This means that if the viewport is less than 500px, use a source of 1000px width. With the <Image/> component, you can specify the sizes like the following:
<Image
src="image-src"
alt="image-alt-text"
sizes="320 640 750"
layout="responsive"
/>
Keep in mind that it is recommended to define sizes only when using a responsive or fill layout.
quality propThe quality prop provides an integer between 1 and 100 that defines the quality of the optimized image; 1 being the worst quality and 100 being the best. It defaults to 75:
<Image
src="image-src"
alt="image-alt-text"
quality={100}
layout="fill"
/>
priority propBy default, images are not prioritized (because they are lazy-loaded), meaning priority defaults to false . When true, the image is considered high-priority and preloaded.
This should only be used when the image is visible above the fold:
<Image
src="image-src"
alt="image-alt-text"
width={500}
height={300}
priority
/>
layout propThe layout prop controls the layout behavior of the image as the size of the viewport changes. The accepted value is a string of either intrinsic , fixed , responsive , or fill.
Each of the layout values has their nuances in:
srcSet and sizesdisplay or position value on the parent element for the corresponding <Image/> element on which they’re usedLet’s take a look at the possible layout values
intrinsic layoutThe intrinsic layout is the default of the four layout values. Using this layout for smaller viewports scales down image dimensions while using it for larger viewports maintains the original image dimensions. You can see an example of intrinsic layout here.
fixed layoutThe fixed layout is similar in behavior to the native img element. With it, image dimensions remain fixed at their original dimensions regardless of viewport changes, meaning there is no response. You can see an example of a fixed layout here.
responsive layoutThe responsive layout borrows from and overrides both the fixed and intrinsic layouts.
To override the fixed layout, it responds to viewport changes, but to override the intrinsic layout for larger viewports, where the image dimensions scale up, the parent element must be display: block. You can see an example of a responsive layout here.
fill layoutThe fill layout responds to its parent dimensions. With it, the image dimensions are stretched to the parent’s dimensions, provided the parent is position: relative.
This is usually paired with the objectFit property. You can see an example of a responsive layout here.
placeholder propThis placeholder property is used as a fallback image when an image is loading. Its possible values are blur or empty.
placeholder defaults to empty, and when it is empty, there is no placeholder while the image is loading, only empty space.
However, when it’s blur, the blurDataURL property is used as the placeholder. If the image src is a static import with the MIME-type jpg, png, or webp, the blurDataURL automatically populates.
For dynamic images, you must provide the blurDataURL property. Solutions such as Plaiceholder can help with base64 generation.
objectFit propThe objectFit prop is similar to the object-fit CSS property that sets how an image should resize to fit its container. It is used with layout=fill or an image with a set width and height and has a possible value of contain, cover, fill, none, and scale-down:
<Image
src="image-src"
alt="image-alt-text"
layout="fill"
objectFit="contain"
/>
objectPosition propThis is similar to the object-position CSS property that specifies the position of an image in its container. It is used with layout=fill or an image with a set width and height and a position value:
<Image
src="image-src"
alt="image-alt-text"
layout="fill"
objectPosition="top right"
/>
loading propThe loading prop is similar to the HTML img element’s loading attribute used for lazy loading. The possible value is a string of lazy or eager:
<Image
src="image-src"
alt="image-alt-text"
layout="fill"
loading="lazy"
/>
It is recommended that images above the fold be loaded with priority instead of loading=“eager” because this hurts performance.
onLoadingComplete propThe onLoadingComplete prop is a callback function that executes immediately after the image completely loads and the placeholder is removed:
<Image
src="image-src"
alt="image-alt"
layout="fill"
// returns:
// {naturalWidth: <imageNaturalWidth>, naturalHeight: <imageNaturalHeight>}
onLoadingComplete={(imageDimension) => console.log(imageDimension)}
/>
blurDataURL propThe blurDataURL 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”:
import Image from 'next/image';
import cardImage from '../public/defaultCardImage.webp';
export default function CardImage() {
return (
<div classname="cardImageWrapper">
<Image
src={cardImage}
alt="image-alt-text"
placeholder="blur"
// width, height, and blurDataURL are automatically provided
/>
</div>
)
}
This data is automatically provided for statically imported images. For dynamic or remote images, you must provide width, height, and blurDataURL manually.
You can see this example of the default blurDataURL prop as well as the shimmer effect with blurDataURL prop.
lazyBoundary propThe lazyBoundary prop is similar to rootMargin in the Intersection Observer API, which acts as the marginal threshold for detecting intersections before triggering lazy loading. It defaults to 200px.
unoptimized propWhen the unoptimized prop is true, the src image will be served as-is instead of changing quality, size, or format:
<Image
src="image-src"
alt="image-alt-text"
width={700}
height={450}
unoptimized
/>
This prop defaults to false.
Apart from the properties listed above, other properties passed to the <Image/> component will relay to the underlying img element with the exception of the following:
decoding is always "async"ref, use onLoadingComplete insteadsrcSet, use deviceSizes insteadstyle, use className insteadTo maintain the aspect ratio of an image and prevent the Core Web Vital and Cumulative Layout Shift, next/image wraps the img element with other div elements.
To style the source image, name it with the className prop then target it in your CSS:
<Image
src="image-src"
alt="image-alt-text"
width={700}
height={450}
// You can style this image component with the `cardImage` class name
className="cardImage"
/>
next/image in next.config.jsnext/image can be configured via next.config.js. Let’s take a look at some of the configurations.
domainsBy default, Next.js only optimizes images hosted on the same domain as your Next.js app. If your images are hosted externally on your CMS, for example, you must specify which domains are allowed to be optimized. This level of specificity is needed to prevent the abuse of external URLs:
module.exports = {
images: {
// assuming you were using the Sanity.io image CDN
// domains is an array of comma-separated strings
// ['cdn.sanity.io', 'cdn.not-sanity.io', 'another domain']
domains: ['cdn.sanity.io'],
}
}
Keep in mind that when loader is set to an external image service, the domains config is ignored.
loaderBy default, Next.js handles image optimization but you can hand that responsibility over to a cloud provider like Cloudinary or imgix that is more dedicated to images than just general optimization.
To do this set the loader and path to allow the use of relative URLs:
module.exports = {
images: {
loader: 'cloudinary',
path: 'https://your-site.com/assets/images/'
}
}
Caching is a rather intricate and, some say, one of the two hardest things in computer science.
In this context, caching speeds up image delivery to users because it avoids refetching over the network.
The Next.js docs have a sufficient explanation forcaching on the default loader. However, if you use a different loader, like Cloudinary, you must refer to that documentation to see how to enable caching.
While not always necessary, there are advanced use cases available for optimizing images. However, be aware that if configuring any properties in this section, it will override any change to the Next.js defaults in future updates.
Nevertheless, let’s see what they are.
deviceSizes and imageSizesBoth device and image sizes are similar with subtle differences. They are both used on the merit that the device widths from the users of your website are known in advance. And they represent a list of device width breakpoints:
module.exports = {
images: {
// the sizes define below are the defaults
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
}
}
deviceSizes is effectual when the <Image/> uses a responsive or fill layout and imageSizes is effectual when the <Image/> uses a fixed or intrinsic layout.
minimumCacheTTLYou can also configure how long or time-to-live (TTL) in seconds for cached optimized images with minimumCacheTTL:
module.exports = {
image: {
// This is 60 seconds
minimumCacheTTL: 60,
}
}
The docs advise that it is better to use a Static Image Import, which automatically handles hashing file contents and caching the file forever. But, keep in mind that you can disable static imports, so choose your battles wisely.
disableStaticImportsIf you have your reasons (I haven’t personally come across one), it is possible to disable static imports:
module.exports = {
images: {
disableStaticImages: true
}
}
To ensure your users get the most optimal image on their devices, images are served with formats like WebP in supported browsers, allowing developers to serve lighter images to users to increase speed while preserving as much fidelity and quality as possible.
Different image formats have their use-cases. WebP is well supported and is a great choice for animated images, offering better compression than PNG or JPEG.
Since Next.js optimizes images in this format, the visual stability of a Next.js site isn’t bogged down by the effects of Cumulative Layout Shift and you can score high on Core Web Vitals.
Image optimization in Next.js improves the user and developer experience with a native game-changing and powerful API that’s easy to work with and extend. This inadvertently solves a major Core Web Vitals need and helps websites achieve a higher SEO rank, all starting and ending with next/image.
Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your Next.js apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now
From basic syntax and advanced techniques to practical applications and error handling, here’s how to use node-cron.

The Angular tree view can be hard to get right, but once you understand it, it can be quite a powerful visual representation.

Build a fast, real-time app with Relay 17 to leverage features like optimistic UI updates, GraphQL subscriptions, and seamless data syncing.

Simplify component interaction and dynamic theming in Vue 3 with defineExpose and for better control and flexibility.
One Reply to "Next.js automatic image optimization with <code>next/image</code>"
Anyone has problems with the quality prop? While my app running in dev mode all my served images are small in size. After the app got builded the pictures are served in original sizes. It seems that the quality prop doesn’t has a effect on it.