images

Configures the built-in Image Optimization API: allowed hosts, widths, formats and cache TTL.

Signature
images?: {
  remotePatterns?: (URL | { protocol?: 'http' | 'https'; hostname: string; port?: string; pathname?: string; search?: string })[]
  localPatterns?: { pathname?: string; search?: string }[]
  deviceSizes?: number[]
  imageSizes?: number[]
  qualities?: number[]
  formats?: ('image/webp' | 'image/avif')[]
  minimumCacheTTL?: number
  dangerouslyAllowSVG?: boolean
  contentDispositionType?: 'inline' | 'attachment'
  contentSecurityPolicy?: string
  loader?: 'default' | 'custom'
  loaderFile?: string
  unoptimized?: boolean
  path?: string
  disableStaticImages?: boolean
}
  • Added in Next.js v10.0.0

Parameters

ParameterTypeDescription
$remotePatternsoptional(URL | RemotePattern)[]= []Allowlist of external sources. Each entry is a URL object or an object with protocol, hostname, port, pathname and search. `*` matches one path segment or subdomain; `**` matches any number of segments at the end of a pathname or the start of a hostname, never in the middle. A src that matches nothing responds 400.
$localPatternsoptional{ pathname?: string; search?: string }[]Allowlist for local paths. When set, src must start with a listed pathname; omitting search allows every query string.
$deviceSizesoptionalnumber[]= [640, 750, 828, 1080, 1200, 1920, 2048, 3840]Device width breakpoints used to build srcset for full-width images.
$imageSizesoptionalnumber[]= [32, 48, 64, 96, 128, 256, 384]Extra widths used only for images that pass a sizes prop. All values should be smaller than the smallest deviceSizes entry.
$qualitiesoptionalnumber[]= [75]Allowlist of quality values. A quality prop outside the list is coerced to the closest allowed entry; a direct API request with an unlisted quality responds 400.
$formatsoptional('image/webp' | 'image/avif')[]= ['image/webp']Output formats offered, in priority order, matched against the request Accept header. No match, or an animated source, falls back to the original format.
$minimumCacheTTLoptionalnumber= 14400Seconds an optimized image stays cached. The effective max-age is this value or the upstream Cache-Control, whichever is larger.
$dangerouslyAllowSVGoptionalboolean= falseAllows SVG sources through the optimizer. SVG can carry scripts, so pair it with contentSecurityPolicy and contentDispositionType.
$contentDispositionTypeoptional'inline' | 'attachment'= 'attachment'Content-Disposition header on optimized responses. attachment forces a download when the URL is visited directly.
$contentSecurityPolicyoptionalstringContent-Security-Policy header sent with optimized images.
$loaderoptional'default' | 'custom'= 'default'Set to 'custom' to hand URL construction to loaderFile instead of the built-in optimizer.
$loaderFileoptionalstringPath relative to the project root of a module whose default export returns a URL string from { src, width, quality }.
$unoptimizedoptionalboolean= falseServes every source as-is, with no resizing or format change.
$pathoptionalstring= '/_next/image'Prefix for the Image Optimization API endpoint.
$disableStaticImagesoptionalboolean= falseDisables static file imports such as import icon from './icon.png'.

Errors

An image whose src does not match remotePatterns or localPatterns responds with 400 Bad Request at request time. A quality prop outside the qualities allowlist is not an error — it is coerced to the closest allowed value, with a warning logged in development — but a direct request to the Image Optimization API with an unlisted quality responds with 400 Bad Request.

Changelog

  • PHP v16.0.0qualities default changed to [75]; maximumRedirects and dangerouslyAllowLocalIP added.
  • PHP v15.3.0remotePatterns accepts an array of URL objects.
  • PHP v15.0.0contentDispositionType default changed to attachment.
  • PHP v14.2.23qualities added.
  • PHP v14.2.15localPatterns added.
  • PHP v14.0.0domains deprecated in favour of remotePatterns.
  • PHP v12.3.0remotePatterns and unoptimized became stable.

The optimizer is opt-in by host. Until a hostname appears in remotePatterns, every external src answers 400 Bad Request — nothing fails at build time, so the breakage shows up in the browser after deploy.

When to reach for it

  • Adding a CMS, S3 bucket or avatar host as an image source.
  • Turning on AVIF, or raising minimumCacheTTL to cut optimizer cost.
  • Handing optimization to Cloudinary, Imgix or Cloudflare with loader: 'custom'.
  • Disabling optimization entirely for a static export.

What trips people up

Omitting protocol, port, pathname or search implies **, which quietly opens the pattern far wider than intended — spell them out. ** is only legal at the end of a pathname or the start of a hostname, never in the middle. Since v16 qualities defaults to [75], so quality={90} is silently served as 75 unless you list 90. A redirect from an allowed host is followed without re-checking the patterns. And there is no cache invalidation: a long minimumCacheTTL can only be cleared by changing the src or deleting <distDir>/cache/images.

Example

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

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'assets.example.com',
        port: '',
        pathname: '/account123/**',
        search: '',
      },
    ],
    formats: ['image/avif', 'image/webp'],
    qualities: [50, 75, 100],
    minimumCacheTTL: 2678400, // 31 days
  },
}

export default nextConfig

When to use it

  • Allow a headless CMS media domain so next/image stops returning 400
  • Serve AVIF with a WebP fallback to shrink hero images
  • Point optimization at Cloudinary while keeping the next/image component
  • Ship a static export by disabling the default optimizer

Frequently asked questions

Why does my external image return 400 Bad Request?

Its hostname is not in images.remotePatterns. The optimizer rejects any src it has not been told to allow, and the check happens per request, so the build succeeds and only the browser shows the failure. Add an entry with protocol, hostname, pathname and search spelled out.

Why is quality={90} being served at 75?

Since Next.js 16 the qualities allowlist defaults to [75], and a quality prop outside the list is coerced to the closest allowed value. Add 90 to images.qualities. Development logs a warning when this coercion happens.

How do I clear the optimized image cache?

There is no invalidation API. You must change the src URL or delete the cached files in <distDir>/cache/images, which is why a very large minimumCacheTTL is risky on content that can change.

More examples

Custom loader for an external optimizer

With loader: 'custom' the /_next/image endpoint is bypassed entirely; next/image renders whatever URL the loader returns. The loader file must live inside the project and default-export the function, and because the function is serialized to the client it runs as client code. This is the supported way to keep next/image while deploying output: 'export'.

Example · typescript
// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  images: {
    loader: 'custom',
    loaderFile: './my-loader.ts',
  },
}

export default nextConfig

// my-loader.ts
export default function cloudinaryLoader({
  src,
  width,
  quality,
}: {
  src: string
  width: number
  quality?: number
}) {
  const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
  return `https://res.cloudinary.com/demo/image/upload/${params.join(',')}${src}`
}

Allowing SVG without opening an XSS hole

SVG is refused by default because it can execute script like HTML. The three settings together allow it while forcing a download rather than a render on direct visit and blocking any embedded script. For a known .svg src the better answer is still the unoptimized prop, which Next.js applies automatically when the src ends in .svg.

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

const nextConfig: NextConfig = {
  images: {
    dangerouslyAllowSVG: true,
    contentDispositionType: 'attachment',
    contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
    localPatterns: [{ pathname: '/assets/icons/**', search: '' }],
  },
}

export default nextConfig

Discussion

  • Be the first to comment on this lesson.