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.
What next/image does for you
Next.js's Image component automatically generates:
- A
srcsetwith several widths of the image. - Conversion to modern formats depending on the browser (
Acceptheader). loading="lazy"by default.widthandheightattributes 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:
- 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.
- For static sites (
output: "export") without an image server, generate the AVIF/WebP variants yourself and use<picture>directly orunoptimized.
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(orpreload) and no lazy loading. sizeson every responsive image and everyfillimage.- Originals resized before adding them to the repo.
- Descriptive
alton 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.