Next.js Image Optimization: The Image Component Guide for Next.js 16
Optimize images in Next.js 16 with next/image: sizing, fill and sizes, remotePatterns, preload (which replaced priority), placeholders, the new qualities default, and Core Web Vitals tips.
On this page (11)
The Next.js Image component (next/image) automatically resizes, compresses and lazy-loads images, serves modern formats like WebP and AVIF, and prevents layout shift. Using it correctly is one of the easiest wins for page speed and Core Web Vitals, which also helps SEO.
Next.js 16 changed several defaults, and AI agents trained on older code often use the deprecated priority prop or images.domains config. This guide covers the current way. New to Next.js? Start with Getting Started with Next.js.
Why use next/image?
- Right size for every device: generates a responsive
srcsetautomatically. - Modern formats: serves WebP or AVIF when the browser supports them.
- Lazy loading by default: offscreen images load only as users scroll.
- No layout shift: reserves space so content doesn't jump (better CLS).
- On-demand optimization: images are optimized when first requested, then cached.
Basic usage
import Image from 'next/image';
export default function Avatar() {
return <Image src="/team/alex.jpg" alt="Alex, our lead designer" width={320} height={320} />;
}
srcis relative to thepublicfolder.altis required. Describe the image for screen readers and search engines, or usealt=""for purely decorative images.widthandheightset the aspect ratio and intrinsic size.
Static imports (easiest)
import Image from 'next/image';
import hero from '@/public/hero.jpg';
export default function Hero() {
return <Image src={hero} alt="Laptop showing a code editor" placeholder="blur" />;
}
When you import an image file, Next.js reads its dimensions and generates a blur placeholder for you, so no width, height or blurDataURL needed.
Remote images
Allow external hosts with remotePatterns in next.config.ts. (images.domains is deprecated in Next.js 16.)
// next.config.ts
const nextConfig = {
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'images.unsplash.com' },
{ protocol: 'https', hostname: 'cdn.example.com', pathname: '/uploads/**' },
],
},
};
export default nextConfig;
Be specific with patterns. Wildcards like hostname: '**' let anyone use your server to optimize arbitrary images.
Responsive images with fill and sizes
When you don't know the dimensions, or want an image to fill its container, use fill with a positioned parent:
<div className="relative aspect-video w-full">
<Image
src="/screenshot.png"
alt="Dashboard screenshot"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 600px"
className="object-cover"
/>
</div>
Always set sizes with fill or responsive layouts. It tells the browser how wide the image will display so it downloads the smallest suitable file. Without it, the browser may download a huge image for a small slot.
Loading your LCP image fast: preload replaces priority
The largest image visible when the page loads (often a hero image) is usually your Largest Contentful Paint (LCP) element. It should load immediately, not lazily.
In Next.js 16 the priority prop is deprecated. Use one of these instead:
// Most cases: load eagerly with high fetch priority
<Image src={hero} alt="..." loading="eager" fetchPriority="high" />
// Or insert a <link rel="preload"> in the head
<Image src={hero} alt="..." preload />
The Next.js docs recommend loading="eager" or fetchPriority="high" in most cases. Use these only for the one or two images that are visible immediately; everything else should stay lazy.
Placeholders
<Image src={photo} alt="..." placeholder="blur" /> // static import: automatic
<Image src="/photo.jpg" alt="..." width={800} height={600}
placeholder="blur" blurDataURL="data:image/png;base64,..." /> // remote/dynamic
<Image src="/photo.jpg" alt="..." width={800} height={600} placeholder="empty" />
Next.js 16 default changes to know
| Setting | Old default | Next.js 16 default |
|---|---|---|
images.qualities | Any quality allowed | [75] only |
images.minimumCacheTTL | 60 seconds | 4 hours |
images.imageSizes | Included 16 | 16 removed |
images.maximumRedirects | Unlimited | 3 |
| Local images with query strings | Allowed | Require localPatterns.search |
If you set quality={90} on an image, it will now be coerced to 75 unless you add 90 to images.qualities:
const nextConfig = {
images: { qualities: [75, 90] },
};
Common patterns
Avatar
<Image src={user.avatarUrl} alt={user.name} width={48} height={48} className="rounded-full" />
Gallery grid
<div className="grid grid-cols-2 gap-4 md:grid-cols-3">
{photos.map((photo) => (
<div key={photo.id} className="relative aspect-square">
<Image src={photo.url} alt={photo.alt} fill sizes="(max-width: 768px) 50vw, 33vw" className="rounded-lg object-cover" />
</div>
))}
</div>
Social share images don't use next/image at all; generate them with opengraph-image files, as covered in our Next.js SEO guide.
Troubleshooting
- "hostname is not configured" → add it to
remotePatterns. - Blurry images → check
sizes, and whether yourqualityis being coerced to 75. - Layout shift → provide
width/height, use a static import, or usefillinside a sized container. - LCP warning in Lighthouse → add
loading="eager"andfetchPriority="high"to the hero image. - Images 404 in production → paths are case-sensitive on most hosts.
Prompt for your agent
Audit every <img> and next/image usage in this Next.js 16 project:
replace raw <img> tags with next/image, add meaningful alt text, add `sizes`
wherever `fill` is used, replace deprecated `priority` with loading="eager" and
fetchPriority="high" on the LCP image only, and move images.domains to remotePatterns.
See our prompting guide for more, and the official Image component docs (opens in a new tab) for every option.
Next steps
- #Next.js
- #Performance
- #Images
- #Core Web Vitals