Lesson 20 of 2222 min read

Next.js Image Optimization Using next/image

Learn how the next/image component automatically optimizes images in Next.js, covering lazy loading and configuring remote image patterns.

Author: CodersNexus

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

FeaturePlain <img>next/image
Automatic resizing to display sizeNoYes
Modern format conversion (WebP/AVIF)NoYes, automatic
Lazy loading by defaultBrowser-dependent, not guaranteedYes, by default
Prevents layout shiftNo, unless manually sized via CSSYes, via required width/height or fill
External domain imagesWorks with any URLRequires 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?

  1. A unique key prop
  2. Specifying width and height (or using the fill prop)
  3. Using only local images
  4. 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?

  1. They load immediately regardless of position
  2. They are lazy loaded, deferred until near the viewport
  3. They never load until manually clicked
  4. 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?

  1. It increases the image's file size
  2. It opts the image out of lazy loading, loading it immediately
  3. It converts the image to a different format
  4. 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?

  1. A custom domain redirect
  2. remotePatterns, allowlisting the external hostname
  3. A new API route
  4. 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?

  1. By hiding all images until the page fully loads
  2. By reserving the correct amount of space based on known width/height before the image downloads
  3. By disabling all other page content while loading
  4. 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.

Frequently Asked Questions

next/image automatically resizes images to their actual display size, converts them to modern, smaller formats for supporting browsers, lazy loads images not yet visible by default, and prevents layout shift — all optimizations a plain <img> tag doesn't provide out of the box.

Providing known dimensions allows Next.js to reserve the correct amount of space for the image in the page layout before it finishes downloading, which is exactly what prevents the jarring layout shift that occurs with plain images of unknown size.

The fill prop makes an image expand to fill its parent container's dimensions, useful when an image's exact size depends on a responsive or dynamically sized container rather than being known as fixed pixel values ahead of time.

Yes, unless you explicitly add the priority prop to opt a specific image out of lazy loading, which is typically reserved for critical, above-the-fold images that should load immediately.

For security, Next.js requires you to explicitly allowlist external hostnames via remotePatterns in next.config.js before it will fetch and optimize images from that domain, preventing your server from being used to process arbitrary, unvetted external URLs.

Yes, local images from public/ work with next/image without any remotePatterns configuration, since they're already part of your own project rather than an external source.

Next.js can automatically serve modern formats like WebP or AVIF to browsers that support them, based on the browser's capabilities, falling back to the original format for browsers that don't support these newer formats.

No — adding priority to many or all images defeats the purpose of lazy loading, since it forces everything to load immediately regardless of visibility, which can actually slow down the perceived performance of the initial page load rather than improving it.

Indirectly, yes — faster page loads and reduced layout shift (both improved by next/image) are factors search engines consider as part of overall page experience and Core Web Vitals metrics, making next/image a meaningful contributor to SEO performance.

Yes, though for very small decorative icons, some developers prefer using inline SVG or a dedicated icon component library instead, since next/image's optimization pipeline is primarily designed for photographic and larger raster images rather than tiny vector icons.