<Image>

Serves optimized, correctly sized images with reserved space so layout does not shift while loading.

Signature
import Image from 'next/image'

<Image
  src={string | StaticImport}   // required
  alt={string}                  // required
  width={number}
  height={number}
  fill={boolean}                // default: false
  loader={({ src, width, quality }) => string}
  sizes={string}
  quality={number}              // default: 75
  preload={boolean}             // default: false
  placeholder={'empty' | 'blur' | `data:image/${string}`} // default: 'empty'
  blurDataURL={string}
  loading={'lazy' | 'eager'}    // default: 'lazy'
  decoding={'async' | 'sync' | 'auto'} // default: 'async'
  unoptimized={boolean}         // default: false
  overrideSrc={string}
  style={object}
  onLoad={(event) => void}
  onError={(event) => void}
/>
  • Added in Next.js v10.0.0

Parameters

ParameterTypeDescription
$srcstring | StaticImportAn internal path, an absolute external URL that matches images.remotePatterns, or a static import. A static import also supplies width, height and blurDataURL automatically.
$altstringAlternative text. Required since v13.0.0; pass an empty string for decorative images.
$widthoptionalnumberIntrinsic width in pixels, used to reserve space and derive the aspect ratio. It does not set the rendered size - CSS does.
$heightoptionalnumberIntrinsic height in pixels. Required together with width unless the image is a static import or uses fill.
$filloptionalboolean= falseMakes the image expand to fill its nearest positioned ancestor, which must have position relative, fixed or absolute.
$loaderoptional({ src, width, quality }) => stringCustom function returning the URL for a given width and quality. Passing it as a prop requires a Client Component; use images.loaderFile to apply one globally.
$sizesoptionalstringMedia-query list telling the browser the rendered width at each breakpoint. Its presence also switches srcset generation from device pixel ratios (1x, 2x) to width descriptors (640w, 750w and so on).
$qualityoptionalnumber= 75Integer from 1 to 100. Values outside the images.qualities allowlist are coerced to the closest allowed entry.
$preloadoptionalboolean= falseInserts a <link rel="preload"> in the head. Use it on the LCP element only, and not together with loading or fetchPriority.
$priorityoptionalboolean= falseDeprecated since v16.0.0 in favour of preload, which names the behaviour it actually performs.
$placeholderoptional'empty' | 'blur' | data:image/...= 'empty'What to show while loading. 'blur' requires blurDataURL, which a static import provides automatically for jpg, png, webp and avif.
$blurDataURLoptionalstringTiny data URL enlarged and blurred behind the image. Keep it 10px or smaller - a large one is shipped inline in the HTML.
$loadingoptional'lazy' | 'eager'= 'lazy''lazy' defers loading until the image nears the viewport; 'eager' loads it immediately.
$decodingoptional'async' | 'sync' | 'auto'= 'async'Hint about whether the browser should wait for decoding before presenting other content updates.
$unoptimizedoptionalboolean= falseServes the source as-is without changing quality, size or format. Use for SVG, animated GIF, images under about 1KB, or sources that need request headers.
$overrideSrcoptionalstringReplaces the generated src attribute while leaving srcset intact, so an existing URL keeps its SEO ranking after a migration from <img>.
$styleoptionalobjectCSS applied to the underlying img element, for example { objectFit: 'cover' }.
$onLoadoptional(event) => voidFires once the image has fully loaded and the placeholder is removed; event.target references the img element. Requires a Client Component.
$onErroroptional(event) => voidFires when the image fails to load. Requires a Client Component.

Return value

JSX.ElementAn <img> element with generated srcset and src attributes pointing at the Image Optimization endpoint, plus intrinsic sizing attributes.

Errors

Next.js errors at render time when alt is missing, when width and height are absent on an image that is neither statically imported nor using fill, and the optimizer responds 400 when a remote src host is not listed in images.remotePatterns.

Changelog

  • PHP v16.0.0priority deprecated in favour of preload; the default images.qualities became [75].
  • PHP v15.0.0The Content-Disposition of optimized responses defaults to attachment.
  • PHP v14.2.23images.qualities allowlist added - a quality value outside it is coerced to the nearest allowed entry.
  • PHP v14.2.0overrideSrc prop added.
  • PHP v14.0.0onLoadingComplete deprecated in favour of onLoad; the images.domains config deprecated in favour of remotePatterns.
  • PHP v13.0.0The old component moved to next/legacy/image. The <span> wrapper was removed, layout, objectFit, objectPosition, lazyBoundary and lazyRoot were removed, and alt became required.

<Image> wraps <img> and adds three things you would otherwise build by hand: on-demand resizing and format conversion through the Image Optimization endpoint, a generated srcset, and reserved space so the page does not reflow when the file arrives.

Choosing how to size it

Static imports are the easiest path — the build reads the file and fills in width, height and blurDataURL for you. For a remote or dynamic src you must supply width and height, or use fill and give the parent position: relative. Those numbers describe the intrinsic size used for the aspect ratio; CSS still controls how large it renders.

The two mistakes that cost the most

  • Omitting sizes on a responsive or fill image. The browser then assumes 100vw and downloads a desktop-sized file onto a phone.
  • Marking every image as important. preload belongs on the single LCP element. Preloading a gallery pushes the real hero down the network queue.

Remote sources must be allowlisted in images.remotePatterns, and the optimizer never forwards request headers — an authenticated source needs unoptimized.

Example

Example · typescript
import Image from 'next/image'
import hero from './hero.jpg'

export default function Page() {
  return (
    <Image
      src={hero}
      alt="Sunrise over the harbour"
      placeholder="blur"
      preload
      sizes="(max-width: 768px) 100vw, 768px"
      style={{ width: '100%', height: 'auto' }}
    />
  )
}

When to use it

  • Render a hero image that is the LCP element without shifting the headline below it.
  • Fill a fixed-ratio card with a cropped photo using fill plus objectFit: cover.
  • Serve user-uploaded photos from an external CDN through an allowlisted remote pattern.
  • Keep an existing src attribute after migrating an <img> tag, using overrideSrc, so search rankings survive.

Frequently asked questions

Why does my remote image return a 400 error?

The host is not listed in images.remotePatterns in next.config.js, so the Image Optimization endpoint refuses to fetch it. Add a pattern matching the protocol, hostname and pathname, then restart the dev server.

Do I have to pass width and height?

Only when the src is a string. A static import supplies both from the file at build time, and the fill prop replaces them by stretching the image to a positioned parent.

What replaced the priority prop?

preload, as of Next.js 16 - priority is deprecated but still works. Use it on the single largest above-the-fold image, and not alongside loading or fetchPriority.

More examples

A remote image filling a fixed-ratio container

fill removes the need to know the file's dimensions, but it only works because the wrapper is positioned and has an aspect ratio - without that the image collapses to zero height. The sizes value tells the browser this is a third-of-a-row card on desktop, so on a 1280px viewport it needs about 420px of width and picks the 640w entry from the generated srcset rather than a full-width 1200w or 1920w file. Next.js only ever generates the widths in images.deviceSizes ([640, 750, 828, 1080, 1200, 1920, 2048, 3840]) plus images.imageSizes ([32, 48, 64, 96, 128, 256, 384]), so the browser always lands on one of those candidates and never on an arbitrary intermediate size.

Example · typescript
import Image from 'next/image'

export function Card({ photoUrl, title }: { photoUrl: string; title: string }) {
  return (
    <article>
      <div style={{ position: 'relative', aspectRatio: '16 / 9' }}>
        <Image
          src={photoUrl}
          alt={title}
          fill
          sizes="(max-width: 640px) 100vw, 33vw"
          style={{ objectFit: 'cover' }}
        />
      </div>
      <h2>{title}</h2>
    </article>
  )
}

Allowlisting a remote host

Every external src is refused until its host, and optionally its path and query, match an entry here. The qualities allowlist is equally strict in a quieter way: with this config a quality={80} prop is served as 75 and only logs a warning in development.

Example · typescript
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.example.com',
        pathname: '/uploads/**',
        search: '',
      },
    ],
    qualities: [50, 75, 100],
  },
}

export default nextConfig

A custom loader for a third-party CDN

The loader is called once per entry in the generated srcset, which is why it receives width rather than reading it off the props. Passing a function as a prop is what forces the 'use client' directive here; setting images.loaderFile in next.config.js applies the same loader everywhere without that constraint.

Example · typescript
'use client'

import Image from 'next/image'

type LoaderArgs = { src: string; width: number; quality?: number }

function cloudinaryLoader({ src, width, quality }: LoaderArgs) {
  const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 75}`]
  return `https://res.cloudinary.com/demo/image/upload/${params.join(',')}${src}`
}

export function Avatar({ path }: { path: string }) {
  return (
    <Image
      loader={cloudinaryLoader}
      src={path}
      alt=""
      width={64}
      height={64}
    />
  )
}

Discussion

  • Be the first to comment on this lesson.