Poorly-handled images remain the #1 cause of slow pages and failing Core Web Vitals. In the latest HTTP Archive run (May 2025) images made up 52 % of the median mobile transfer size, and they directly drive the Largest Contentful Paint (LCP) metric that now influences Google search rank. Next.js tackles this problem with a first-class Image Optimization API and the <Image>
component.
This guide walks through every feature, configuration option, and gotcha you need to master.
1 — Why use next/image
instead of raw <img>
?
-
Automatic responsive output — Next.js emits a
srcset
so each device fetches only the pixels it needs, served in modern formats (AVIF/WebP). -
Built-in lazy-loading keeps off-screen images out of the critical path, improving LCP.
-
Blur-up placeholders & fixed dimensions prevent Cumulative Layout Shift (CLS).
-
Edge-scaled remote images let you resize anything from S3, a headless CMS, or user uploads on the fly.
2 — Local vs. remote images
Local imports pick up width/height automatically. Remote URLs need explicit dimensions and must be whitelisted:
3 — Key props & when to use them
Prop | Use it for … | Notes |
---|---|---|
priority |
Your LCP/hero image | Adds <link rel="preload"> + fetchpriority="high" where supported. |
fill |
When the container controls the aspect ratio | Parent must be position: relative . |
sizes |
Pair with fill for a proper srcset |
Example: sizes="(max-width: 768px) 100vw, 50vw" . |
quality |
Fine-tune lossy compression (1–100) | Default 75 is safe; rarely raise it. |
fetchPriority |
Explicitly set high , low , or auto if you must |
priority already handles most cases. |
4 — Tuning next.config.js
export default {
images: {
deviceSizes: [640, 768, 1024, 1280, 1920],
imageSizes: [16, 32, 48, 64, 96],
formats: ['image/avif', 'image/webp'], // order = preference
minimumCacheTTL: 60, // seconds in edge cache
contentDispositionType: 'inline',
dangerouslyAllowSVG: false,
unoptimized: false, // true opts OUT of all transforms
},
};
Keep deviceSizes
≤ 25 and imageSizes
≤ 50 to avoid the “Invalid images config” build error.
5 — Custom loaders & CDN integrations
The built-in loader proxies through your Next.js server. If you’d rather offload work to Cloudinary, Imgix, Thumbor, or a bespoke service:
You can also pass a loader
prop per image if only a few need the custom URL pattern.
6 — Static export caveat (output: 'export'
)
next export
(or output: "export"
) removes the Node runtime that powers on-demand resizing. The default loader then fails with
“Image Optimization API is not available in export”.
Fixes:
-
Use a custom loader that returns already-optimized CDN URLs.
-
Host a lightweight image proxy (Edge Function, Cloudflare Workers, etc.) alongside your static build.
7 — Caching & self-hosting tips
-
Edge cache TTL (
minimumCacheTTL
) — bump to hours for static product shots to slash origin CPU. -
Sharp memory limits — for huge source images set
NODE_OPTIONS="--max_old_space_size=4096"
on your server. -
OG image generation — Next 15 introduces
ImageResponse
helpers for dynamic social cards at the edge.
8 — Security best practices
Risk | Mitigation |
---|---|
Open redirects / SSRF | Use strict remotePatterns instead of wildcard domains . |
SVG script injection | Keep dangerouslyAllowSVG: false unless you sanitize files. |
Bandwidth bombs | Define realistic deviceSizes and convert user uploads. |
9 — Common runtime errors & quick fixes
Error text (abridged) | Cause | Fix |
---|---|---|
image src https://foo not configured |
Host not whitelisted | Add pattern to remotePatterns . |
You must provide width and height |
Remote image missing dimensions | Supply them or use a static import. |
Image Optimization API is not available in export |
Default loader + static export | Switch to custom CDN loader. |
10 — Future-proofing (Next 15 + React 19)
-
AVIF now sits first in the default
formats
array. -
priority
automatically appliesfetchpriority="high"
on Chrome 115+ & Safari 17. -
@vercel/og
edge helpers let you create social OG images in TS/JS right beside your route handlers.
11 — Mini case study 📈
Metric | Before fix | After <Image> |
---|---|---|
LCP (mobile, P95) | 4.2 s | 1.6 s |
CLS | 0.11 | 0.01 |
Image transfer size | 3 MB | 980 KB |
Add-to-cart conversions | — | +23 % |
The Wisp CMS landing page team migrated to <Image>
, enabled AVIF/WebP, and increased edge TTL from 60 s to 1 h.
12 — Workflow tips
-
MDX imports auto-inject dimensions and blur placeholders.
-
Wrap
<Image unoptimized>
in Storybook for screenshot tests (no remote calls). -
Run
npx @next/codemod next-image-to-remotePatterns
when upgrading legacy configs.
13 — Testing & debugging checklist
-
Lighthouse → ensure LCP element = expected hero image.
-
WebPageTest filmstrip → blur placeholder vanishes < 0.5 s on slow 3G.
-
DevTools Network → verify AVIF/WebP
Content-Type
. -
next dev
overlay → hover an image to see actual decoded bytes.
14 — Accessibility & SEO
-
Descriptive
alt
text (oralt=""
for decorative images). -
Generate OG/Twitter cards with
@vercel/og
. -
Avoid embedding essential text inside images (search/lang-translate issues).
15 — Launch checklist ✅
-
Audit every
<img>
; migrate or justify. -
Mark the LCP asset
priority
. -
Define real breakpoint arrays (
deviceSizes
). -
Harden
remotePatterns
; no wildcards. -
Disable SVG unless sanitized.
-
Prefer AVIF → WebP fallback order.
-
Raise edge cache TTL for static assets.
-
Cap user-upload dimensions & convert format.
-
Add Lighthouse perf guardrails in CI.
-
Document your image rules for the team.
Wrap-up 🌟
With a single component and a few lines of config, Next.js turns image optimization from a DevOps chore into a first-class developer primitive. Embrace modern formats, leverage edge caching, and your pages will feel instant—keeping Core Web Vitals (and users) happy.
Happy optimizing! 🎉
FAQ — Image Optimization in Next.js (2025)
# | Question | Quick answer |
---|---|---|
1 | Does next/image support AVIF automatically? |
Yes. AVIF is now the first format in the default formats array, so modern browsers receive AVIF first and fall back to WebP/PNG if unsupported. You can override the order via images.formats in next.config.js . nextjs.org |
2 | How do I allow remote images? | Add each origin to images.remotePatterns (recommended) or the older images.domains array. remotePatterns lets you match protocol, host and path for tighter security. nextjs.org |
3 | What happens if I forget width and height on a remote image? |
Next.js will throw “You must provide width and height” at runtime, because it can’t infer the intrinsic size from a URL alone. Always specify them—or use a static import for local files, which auto-detects size. nextjs.org |
4 | When should I add the priority prop? |
Only to the single image that defines your page’s Largest Contentful Paint (hero banner, product photo). It preloads the file and sets fetchpriority="high" on supporting browsers, improving LCP. dev.to |
5 | Does priority download on every page? |
No. The prop is per-component. Use it sparingly; unnecessary preloads compete for bandwidth and can slow other resources. dev.to |
6 | Can I disable optimisation for one image? | Yes — pass unoptimized on the <Image> element to serve the file exactly as provided (useful for already-compressed SVG or ICO sprites). nextjs.org |
7 | What breaks under next export / output: "export" ? |
The default Image Optimisation API needs a Node runtime, so static export fails with “Image Optimization API is not available”. Switch to a custom loader (Cloudinary, Imgix, DIY edge function) or forego optimisation. nextjs.org |
8 | Does next/image generate files at build time? |
No. All resizing/transcoding happens on demand the first time an image is requested, then it’s cached at the edge for subsequent hits (cache time = minimumCacheTTL ). nextjs.org |
9 | How do I integrate Cloudinary / Imgix? | Set images.loader: "custom" and point loaderFile to a JS module that returns the provider’s URL template, or pass a loader function per image. nextjs.org |
10 | Is SVG safe to serve through next/image ? |
Only if you set images.dangerouslyAllowSVG: true and sanitise files server-side. SVG can embed scripts, so the flag defaults to false . nextjs.org |
11 | Why is my console warning about too many breakpoints? | deviceSizes is limited to 25 values and imageSizes to 50. Exceeding either triggers an “Invalid images config” build error. nextjs.org |
12 | Does sizes matter with the fill prop? |
Absolutely. When you use fill , add a sizes attribute so the browser can choose the correct candidate from the srcset ; otherwise it assumes the image is 100 vw and may download an oversized file. nextjs.org |
Got another question? Drop it below and I’ll update the list! 🎉