NextjsImage Optimization (next/image)

Image Optimization (next/image)

Images are usually the heaviest assets on a page, and a plain <img> tag leaves every optimization decision to you — the right file format, the right size for the viewport, when to load it, and how to prevent it from shifting the layout as it loads in. The <Image> component from next/image handles all of that automatically.

Benefit

What it means in practice

Responsive sizing

Serves an appropriately sized image for the device, instead of shipping one giant file to every screen

Lazy loading by default

Images outside the viewport are not fetched until the user scrolls near them

Automatic format conversion

Serves modern formats like WebP or AVIF to browsers that support them, falling back gracefully otherwise

Layout-shift prevention

Reserves the correct amount of space before the image loads, avoiding Cumulative Layout Shift

A basic example

app/page.tsx

TSX
import Image from 'next/image'
import profilePic from '../public/profile.png'

export default function Page() {
  return (
    <Image
      src={profilePic}
      alt="Author profile picture"
      // width and height are set automatically for static imports
    />
  )
}
Importing a local image file like this gives Next.js the image's intrinsic width and height automatically. For images loaded from a URL — remote images, or images passed as a string path — you have to supply those dimensions yourself.

Remote image — width/height required

TSX
import Image from 'next/image'

export default function Avatar() {
  return (
    <Image
      src="https://example.com/avatar.jpg"
      alt="User avatar"
      width={64}
      height={64}
    />
  )
}
Warning
Unless you use the fill prop, width and height are required for any image loaded from a remote URL or passed as a plain string. Next.js needs those dimensions to compute the correct aspect ratio and reserve space for the image before it downloads — without them, the browser has no idea how much room to leave, and the surrounding content jumps around as the image pops in. Use fill instead of fixed dimensions when the image should stretch to fill a parent container of unknown or dynamic size.

Using fill inside a sized parent

TSX
import Image from 'next/image'

export default function Hero() {
  return (
    <div style={{ position: 'relative', width: '100%', height: 400 }}>
      <Image
        src="/hero.jpg"
        alt="Hero banner"
        fill
        style={{ objectFit: 'cover' }}
      />
    </div>
  )
}
Remote images need explicit configuration
Warning
By default, Next.js refuses to optimize images from domains it doesn't know about — this prevents your server from being used to proxy and transform arbitrary third-party images. Any remote host you load images from must be allow-listed via images.remotePatterns in next.config.mjs, or the <Image> component will throw at request time.

next.config.mjs

JS
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.example.com',
        pathname: '/**',
      },
    ],
  },
}

export default nextConfig
The priority prop
Lazy loading is great for images the user has to scroll to see, but it's counterproductive for the single most important image on the page — typically the one driving your Largest Contentful Paint (LCP) metric, such as a hero banner. Marking that image with priority tells Next.js to preload it and skip lazy loading, so it starts fetching as early as possible.

TSX
<Image
  src="/hero.jpg"
  alt="Hero banner"
  width={1200}
  height={600}
  priority
/>
Tip
Use priority on at most one or two above-the-fold images per page. Marking every image as a priority defeats the purpose — the browser can only truly prioritize a handful of requests at once.
Note
Image optimization happens on demand by default, using the Node.js server's built-in image optimization API. On fully static exports, or on some hosting providers, you may need a custom loader or a different optimization strategy — check your deployment target's documentation.
  • <Image> automatically handles responsive sizing, lazy loading, modern format conversion, and layout-shift prevention.

  • Fixed width/height (or fill for a sized parent) are required so Next.js can reserve space before the image loads.

  • Remote image hosts must be allow-listed via images.remotePatterns in next.config.mjs.

  • Use the priority prop on the page’s LCP image to preload it and skip lazy loading.