Open-Source Wikis

/

Next.js

/

Systems

/

Image optimization

vercel/next.js

Image optimization

Two halves: a React <Image> component on the client, and an HTTP image-optimization endpoint at /_next/image on the server. The endpoint resizes, recodes, and caches images on demand. The client component generates the right srcset and sizes to consume the endpoint.

Components

graph LR
    Source[<img src='/wikis/next-js/systems/hero.jpg'>] --> Component
    Component[next/image client<br/>image-component.tsx] --> Srcset[generates srcset]
    Browser -- /_next/image?url=hero.jpg&w=640 --> Endpoint
    Endpoint[image-optimizer.ts<br/>35 KB] --> Resize[Sharp / Squoosh]
    Resize --> Cache[Disk cache<br/>incremental-cache]
    Cache --> Endpoint
    Endpoint --> Browser

Client component

packages/next/src/client/image-component.tsx (15 KB) is the component user code imports as next/image. It produces an <img> (or <picture> when needed) with:

  • srcset covering the configured deviceSizes and imageSizes from next.config.js.
  • sizes based on the fill, width, or sizes props.
  • loading="lazy" by default; priority prop opts into eager loading and a preload tag.
  • Built-in placeholder support (blur, color).
  • Layout shift prevention through the width and height requirements.

Configuration of the client component reads from images-manifest.json written at build time.

Server endpoint

packages/next/src/server/image-optimizer.ts (35 KB) implements the /_next/image?url=...&w=...&q=... endpoint. It:

  1. Validates the request URL against the configured images.remotePatterns, images.domains, and images.localPatterns allowlists.
  2. Looks up the response in the disk cache (packages/next/src/server/lib/incremental-cache/).
  3. On miss, fetches the source image (local file or remote URL), pipes it through the optimizer, and writes the result to the cache.
  4. Streams back the optimized output with the appropriate Cache-Control and Content-Type headers.

The actual image processing uses Sharp when available (Node's preferred path, much faster) and falls back to a WASM resizer (@squoosh/lib style) when Sharp isn't installed.

Optimization options

Option Source
Output format Decided per request, based on Accept header (AVIF, WebP, fallback to original)
Quality q query param, default 75
Width w query param, must be in deviceSizes or imageSizes
Cache TTL images.minimumCacheTTL config + remote Cache-Control

The framework explicitly rejects arbitrary widths to prevent cache poisoning.

Caching

The endpoint reuses the framework's incremental cache (packages/next/src/server/lib/incremental-cache/). On disk, optimized variants live under .next/cache/images/.

For deployments where the host doesn't want to run image optimization itself, images.loader can be set to 'cloudinary', 'imgix', 'vercel', or a custom loader. The loader-based path generates URLs for an external service; the framework then bypasses the local optimizer.

Static assets

The image component handles three source types:

  • Static imports (import logo from './logo.png') — width and height are known at build time, the component avoids layout shift natively.
  • Local public files — width and height must be supplied by the user.
  • Remote URLs — must match images.remotePatterns. Width and height must be supplied.

Build-time static analysis happens in packages/next/src/build/static-paths/ and the asset path tracking lives in the build manifests.

Edge runtime

When middleware or an edge route emits an image URL, the optimizer endpoint still runs in the Node runtime — the optimizer is too heavy for the edge sandbox. Edge code can reference images and emit URLs but cannot perform optimization itself.

Configuration

User config in next.config.js under the images block:

{
  images: {
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    formats: ['image/avif', 'image/webp'],
    minimumCacheTTL: 60,
    domains: ['example.com'],
    remotePatterns: [{ protocol: 'https', hostname: '**.cdn.example.com' }],
    loader: 'default',
    path: '/_next/image',
  },
}

Schema validation happens in packages/next/src/server/config-schema.ts.

Integration points

  • The build pipeline writes images-manifest.json consumed by both client and server.
  • The endpoint shares the disk cache with ISR (see caching).
  • The client component reads global config from the manifest at hydration time.

Entry points for modification

  • To change the optimizer pipeline: packages/next/src/server/image-optimizer.ts.
  • To change client behavior: packages/next/src/client/image-component.tsx.
  • To add a new format or codec: packages/next/src/server/image-optimizer.ts plus next.config.js schema in config-schema.ts.
  • To add a built-in loader: packages/next/src/shared/lib/image-loaders/.

Key source files

File Purpose
packages/next/src/client/image-component.tsx Client <Image> component
packages/next/src/server/image-optimizer.ts /_next/image endpoint
packages/next/src/server/og/ next/og image generation (separate from this system)
packages/next/src/shared/lib/image-loaders/ Built-in remote loaders
packages/next/src/server/lib/incremental-cache/ Shared disk cache

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Image optimization – Next.js wiki | Factory