Skip to content
ImageZap

Image optimization in Next.js

next/image does much of the work, but its defaults aren't always the best. These are the settings that make a difference.

By 3 min read

What next/image does for you

Next.js's Image component automatically generates:

  • A srcset with several widths of the image.
  • Conversion to modern formats depending on the browser (Accept header).
  • loading="lazy" by default.
  • width and height attributes to prevent CLS.

Images are optimized on demand on the server (or the deployment platform) and cached.

Enable AVIF

By default, Next.js only serves WebP. To serve AVIF to browsers that support it, add the format in next.config:

// next.config.js
module.exports = {
  images: {
    formats: ["image/avif", "image/webp"],
  },
};

Order matters: the first format accepted by the browser wins. AVIF takes longer to generate the first time, but afterwards it's served from cache.

The main image: preload and priority

next/image lazy-loads every image unless told otherwise. For the LCP image:

<Image src={hero} alt="…" priority sizes="100vw" />

In recent versions, the preload prop (or fetchPriority="high" with loading="eager") does the same job as priority. Check the docs for your version: the idea is always the same —disable lazy loading and preload the main image. More context in how to improve LCP.

sizes: the most forgotten setting

Without sizes, Next.js generates a srcset with density descriptors (1x, 2x) based on the width you pass. With sizes, it generates width descriptors and the browser can choose much better:

<Image
  src="/blog/cover.jpg"
  alt="…"
  width={1600}
  height={900}
  sizes="(min-width: 1024px) 768px, 100vw"
/>

If you use fill (the image fills its container), sizes is practically mandatory; otherwise the browser assumes 100vw and downloads images that are too large in column layouts.

Quality

The default is 75. Recent versions require listing allowed qualities in images.qualities if you use others. For photos, 70–80 is usually enough; for product images, perhaps 85.

Optimize on the server or before the build?

On-demand optimization has advantages (automatic variants), but also costs:

  • Slow first request: each size and format combination is generated the first time someone asks for it.
  • Platform costs or limits: some providers charge for or cap image transformations.
  • Heavy static images in the repository: if you commit 8 MB photos, the build and the repo grow.

A sensible strategy:

  1. Optimize originals before adding them to the project. Resize to a reasonable maximum (for example 2560 px) and compress them with ImageZap. The repo stays light and next/image works on smaller files.
  2. For static sites (output: "export") without an image server, generate the AVIF/WebP variants yourself and use <picture> directly or unoptimized.

Remote images

For images from a CMS or external CDN, declare the domains in images.remotePatterns. If the CDN already optimizes and serves AVIF, use a custom loader so Next.js generates CDN URLs instead of re-optimizing.

Checklist

  • formats: ["image/avif", "image/webp"] in the config.
  • The LCP image with priority (or preload) and no lazy loading.
  • sizes on every responsive image and every fill image.
  • Originals resized before adding them to the repo.
  • Descriptive alt on every image.

Frequently asked questions

Does next/image work with static export?

Built-in optimization needs a server. With output: "export" you have to use unoptimized or an external loader.

Why are my images slow the first time?

Because they're being generated. Subsequent requests come from cache.

Should I use next/image for SVG?

It adds nothing: SVGs aren't optimized like raster images. Use a regular <img> or inline SVG.

Can I use files generated by ImageZap with next/image?

Yes. You can import the AVIF or WebP files directly, or use the generated JSX code with <picture> if you'd rather control the formats yourself.

Related guides