Next.js Image Optimization Using next/image
Images are consistently one of the largest contributors to a slow-loading webpage, often accounting for the majority of a page's total download size. A plain HTML <img> tag downloads the file exactly as stored — full resolution, whatever format it was saved in, regardless of how large it's actually displayed on screen or what device is requesting it — leaving an enormous amount of performance on the table.
The next/image component solves this comprehensively: it automatically resizes images to match how they're actually displayed, serves modern, smaller formats like WebP to browsers that support them, lazy loads images that aren't yet visible on screen, and prevents the layout-shifting flicker that occurs when a browser doesn't know an image's dimensions ahead of time. This lesson covers using next/image correctly, understanding its automatic lazy loading behavior, and configuring remote image patterns for images hosted outside your own project.
Learning Objectives
- Use the next/image component in place of a plain HTML <img> tag.
- Understand what automatic optimizations next/image performs.
- Explain how next/image's default lazy loading behavior works.
- Configure remotePatterns to allow optimizing images from external domains.
- Recognize when to use the priority prop to opt out of lazy loading.
Core Definitions
- next/image: A built-in Next.js component that automatically optimizes images — resizing, format conversion, and lazy loading — compared to a plain HTML <img> tag.
- Lazy loading: Deferring the loading of an image until it's about to enter the user's viewport, saving bandwidth and speeding up initial page load for images not yet visible.
- Layout shift: An unwanted visual jump that occurs when content (like an image) loads and changes the page's layout after surrounding elements have already been positioned.
- remotePatterns: A next.config.js setting that explicitly allowlists external domains next/image is permitted to fetch and optimize images from.
- priority prop: A prop on next/image that opts a specific image out of lazy loading, loading it immediately, intended for critical above-the-fold images.
Detailed Explanation
Replacing a plain <img src="..." /> tag with next/image requires specifying width and height (or using the fill prop for a responsive container), and this is intentional, not a limitation: knowing an image's dimensions ahead of time is exactly what allows Next.js to reserve the correct amount of space for it before the image file has even finished downloading, completely eliminating the jarring layout shift that occurs with plain <img> tags when surrounding content jumps around as images pop in.
Beyond preventing layout shift, next/image performs several optimizations automatically, with zero extra configuration required. It resizes the source image to match the actual size it's being displayed at (rather than shipping a needlessly huge original file to be squeezed into a small thumbnail), and it automatically serves modern, more efficient formats like WebP or AVIF to browsers that support them, falling back to the original format for browsers that don't — all of this happens transparently, with Next.js generating and caching the optimized versions on demand.
By default, every next/image is lazy loaded: rather than downloading immediately when the page loads, Next.js waits until the image is about to scroll into the user's viewport before fetching it. This means images far down a long page — say, in a footer or deep in an infinite-scroll feed — never cost any bandwidth or loading time for a visitor who never scrolls that far, a meaningful performance win with zero manual configuration. For the rare cases where you specifically want an image to load immediately regardless of its position — most commonly, a large hero image visible the instant a page loads, sometimes called an 'above-the-fold' image — you explicitly opt out of this default lazy behavior using the priority prop, which tells Next.js to load that specific image eagerly and treat it as a high priority for the page's initial render.
For security and to allow Next.js to actually process and optimize them, images from external domains (rather than your own project's public/ folder) require explicit configuration. Adding a remotePatterns array to next.config.js allowlists exactly which external hostnames next/image is permitted to fetch and optimize images from — attempting to use next/image with a source from a domain not included in this list will fail, a deliberate safety measure preventing your server from being used to fetch and optimize arbitrary, unvetted external URLs.
Diagram Description
Visualize the difference between a plain <img> and next/image:
Plain <img src="huge-photo.jpg">:
[Downloads full original file] --> [Displayed squeezed into a small thumbnail size] --> [Wasted bandwidth, possible layout shift]
next/image with width={400} height={300}:
[Space reserved immediately, no layout shift]
[Lazy loaded — waits until near the viewport, UNLESS priority is set]
[Automatically resized + converted to WebP/AVIF for the requesting browser]
[Result: much smaller download, no visual jump, faster page]
Comparison Table
| Feature | Plain <img> | next/image |
|---|---|---|
| Automatic resizing to display size | No | Yes |
| Modern format conversion (WebP/AVIF) | No | Yes, automatic |
| Lazy loading by default | Browser-dependent, not guaranteed | Yes, by default |
| Prevents layout shift | No, unless manually sized via CSS | Yes, via required width/height or fill |
| External domain images | Works with any URL | Requires remotePatterns configuration |
Next.js Practical Example
// next.config.js — allowlisting an external image domain
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.example-cdn.com',
},
],
},
};
module.exports = nextConfig;
// app/page.tsx — using next/image
import Image from 'next/image';
export default function HomePage() {
return (
<div>
{/* Hero image: loads immediately, opts out of lazy loading */}
<Image
src="/hero-banner.jpg"
alt="Welcome banner"
width={1200}
height={600}
priority
/>
{/* Regular product image: lazy loaded by default */}
<Image
src="https://images.example-cdn.com/products/shoe-1.jpg"
alt="Running shoe"
width={400}
height={400}
/>
</div>
);
}
The remotePatterns configuration explicitly allows next/image to fetch and optimize images from images.example-cdn.com; without this entry, attempting to use that URL as a next/image source would fail. The hero banner image uses the priority prop specifically because it's the first thing a visitor sees on page load — opting out of lazy loading ensures it starts downloading immediately rather than being unnecessarily delayed. The product image, further down the page, uses next/image's default lazy loading behavior, meaning it won't be fetched at all until the user scrolls close enough to see it, saving bandwidth for visitors who don't scroll that far.
Industry Examples
- E-commerce product catalogs use next/image extensively across large grids of product photos, relying on default lazy loading so only visible products' images are ever downloaded as a user scrolls.
- News and media sites use the priority prop specifically for a homepage's lead/hero article image, ensuring it appears instantly, while using default lazy loading for the dozens of smaller thumbnail images further down the page.
- Real estate listing sites configure remotePatterns to allow optimizing property photos hosted on a separate cloud storage or CDN domain, rather than storing every image directly within the Next.js project itself.
- Portfolio and photography sites benefit enormously from next/image's automatic format conversion and resizing, since serving unoptimized, full-resolution photography would otherwise create extremely slow page loads.
- Social media and content platforms use next/image's automatic layout-shift prevention to keep feeds visually stable as images of varying sizes load in during scrolling.
Interview Questions and Answers
Q1. What are the main automatic optimizations next/image performs compared to a plain <img> tag?
next/image automatically resizes images to match their actual display size, converts them to modern, smaller formats like WebP or AVIF for supporting browsers, lazy loads images by default until they're near the viewport, and prevents layout shift by reserving the correct space based on specified width and height.
Q2. Why does next/image require width and height (or the fill prop)?
Knowing an image's dimensions ahead of time allows Next.js to reserve the correct amount of space for it in the layout before the image file finishes downloading, which is exactly what prevents the layout shift that occurs with plain <img> tags when surrounding content jumps as images pop in.
Q3. What is next/image's default lazy loading behavior?
By default, next/image defers downloading an image until it's about to scroll into the user's viewport, rather than loading it immediately with the rest of the page. This saves bandwidth and speeds up initial page load, especially for images positioned far down a long page.
Q4. When would you use the priority prop on a next/image, and why?
You'd use priority on a critical, above-the-fold image — such as a large hero banner visible the instant a page loads — to explicitly opt it out of the default lazy loading behavior, ensuring it starts downloading immediately rather than being unnecessarily delayed.
Q5. Why does next/image require configuring remotePatterns for external image sources?
For security and to allow Next.js to actually process and optimize external images, you must explicitly allowlist which external hostnames are permitted in next.config.js. This deliberate safety measure prevents your server from being used to fetch and optimize arbitrary, unvetted external URLs.
MCQs With Answers
1. What is a key requirement when using next/image that a plain <img> tag doesn't have?
- A unique key prop
- Specifying width and height (or using the fill prop)
- Using only local images
- Wrapping it in a <Link> component
Answer: B. Specifying width and height (or using the fill prop)
Explanation: next/image requires known dimensions (or the fill prop) so it can reserve the correct layout space ahead of time, preventing layout shift.
2. What is next/image's default loading behavior for images not yet visible on screen?
- They load immediately regardless of position
- They are lazy loaded, deferred until near the viewport
- They never load until manually clicked
- They are blocked entirely
Answer: B. They are lazy loaded, deferred until near the viewport
Explanation: By default, next/image defers loading an image until it's about to enter the user's viewport, saving bandwidth for images not yet visible.
3. What does the priority prop do when added to a next/image?
- It increases the image's file size
- It opts the image out of lazy loading, loading it immediately
- It converts the image to a different format
- It hides the image on mobile devices
Answer: B. It opts the image out of lazy loading, loading it immediately
Explanation: priority tells Next.js to load that specific image eagerly, bypassing the default lazy loading behavior, typically used for critical above-the-fold images.
4. What must be configured in next.config.js to use next/image with an external image URL?
- A custom domain redirect
- remotePatterns, allowlisting the external hostname
- A new API route
- The images property must be set to false
Answer: B. remotePatterns, allowlisting the external hostname
Explanation: External image sources must be explicitly allowlisted via remotePatterns in next.config.js before next/image is permitted to fetch and optimize images from that domain.
5. How does next/image help prevent layout shift?
- By hiding all images until the page fully loads
- By reserving the correct amount of space based on known width/height before the image downloads
- By disabling all other page content while loading
- It does not address layout shift
Answer: B. By reserving the correct amount of space based on known width/height before the image downloads
Explanation: Because next/image requires dimensions upfront, Next.js can reserve exactly the right space in the layout immediately, preventing the visual jump that occurs when an image's size is unknown until it loads.
Common Mistakes to Avoid
- Forgetting to specify width and height (or fill) on next/image, resulting in a build/runtime error or unintended layout behavior.
- Using priority on many or all images on a page, which defeats the purpose of lazy loading and can actually slow down perceived performance.
- Forgetting to add an external image domain to remotePatterns, causing next/image to fail for that source.
- Assuming next/image automatically works exactly like a plain <img> tag with no configuration differences, and being surprised by build errors.
- Using next/image for tiny decorative icons where the overhead of its optimization pipeline may not be worth it compared to a simple inline SVG.
Interview Notes
- next/image automatically resizes images, converts them to modern formats, lazy loads by default, and prevents layout shift.
- width and height (or the fill prop) are required so Next.js can reserve correct layout space ahead of time.
- Images are lazy loaded by default; the priority prop opts a specific image out of this for critical above-the-fold content.
- External image sources require explicit allowlisting via remotePatterns in next.config.js.
- next/image is a drop-in performance upgrade over a plain <img> tag for most real-world use cases.
Key Takeaways
- Images are one of the biggest opportunities for performance improvement on most web pages, and next/image addresses this comprehensively with minimal manual effort.
- Default lazy loading combined with the explicit priority opt-out gives fine-grained control over exactly which images load immediately versus on demand.
- Requiring known dimensions isn't a limitation — it's the specific mechanism that lets Next.js eliminate layout shift entirely for optimized images.
- remotePatterns is a deliberate security boundary, not just configuration boilerplate, controlling exactly which external sources your app will fetch and optimize images from.
Summary
The next/image component automatically optimizes images in ways a plain HTML <img> tag cannot: resizing images to match their actual display size, converting them to modern, smaller formats like WebP or AVIF for supporting browsers, and lazy loading images by default so those not yet visible never cost bandwidth until a user scrolls near them. Requiring width and height (or the fill prop) isn't a limitation but the exact mechanism that lets Next.js reserve correct layout space ahead of time, eliminating the layout shift plain images commonly cause. For critical, above-the-fold images that should load immediately rather than lazily, the priority prop explicitly opts out of the default lazy behavior. Images hosted on external domains require explicit allowlisting via remotePatterns in next.config.js, a deliberate security measure ensuring your application only fetches and optimizes images from sources you've specifically approved.