Images are the largest element on most web pages. They directly impact your Largest Contentful Paint (LCP) score and can cause Cumulative Layout Shift (CLS) if not handled correctly. Next.js provides an Image component that handles most optimization automatically.
The Next.js Image Component
import Image from "next/image";
<Image
src="/images/hero.jpg"
alt="Hero banner showing a modern office"
width={1200}
height={600}
priority
/>
This automatically:
- Serves WebP/AVIF format when supported
- Generates responsive sizes
- Lazy loads images below the fold
- Prevents CLS with width/height
- Optimizes quality
Priority Loading for LCP
The hero image or above-the-fold image should use the priority prop:
<Image
src="/images/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority // Preloads this image
/>
priority adds a <link rel="preload"> tag to the document head, telling the browser to fetch this image immediately. Only use it for the LCP element β typically the hero image.
Responsive Images with sizes
The sizes prop tells the browser how wide the image will be at different viewport widths:
<Image
src="/images/feature.jpg"
alt="Feature screenshot"
width={800}
height={500}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
This means:
- On mobile (up to 768px): the image is full viewport width
- On tablet (up to 1200px): the image is 50% viewport width
- On desktop: the image is 33% viewport width
Without sizes, the browser downloads the largest image for every viewport. With proper sizes, mobile users download smaller files.
Fill Mode for Dynamic Sizes
When you do not know the image dimensions ahead of time, use fill:
<div className="relative h-64 w-full">
<Image
src="/images/card-image.jpg"
alt="Card image"
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, 50vw"
/>
</div>
The parent must have position: relative and defined dimensions. The image fills the parent container.
Blur Placeholder
Show a blurred version of the image while it loads:
Static Import (Recommended)
import heroImage from "@/public/images/hero.jpg";
<Image
src={heroImage}
alt="Hero image"
placeholder="blur" // Automatic blur data from static import
priority
/>
Static imports automatically generate blur data at build time. This is the easiest approach.
Dynamic Images
For dynamic images, provide blurDataURL:
<Image
src={imageUrl}
alt="Dynamic image"
width={800}
height={500}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..." // Tiny base64 image
/>
Generate the blur data URL on the server when processing images.
Remote Images
Configure allowed remote image domains in next.config.ts:
// next.config.ts
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "images.unsplash.com",
},
{
protocol: "https",
hostname: "cdn.yourdomain.com",
},
],
},
};
export default nextConfig;
Common Mistakes
1. Missing width and height
Without dimensions, the browser cannot reserve space, causing layout shift (CLS).
// Bad: No dimensions
<Image src="/photo.jpg" alt="Photo" />
// Good: Dimensions provided
<Image src="/photo.jpg" alt="Photo" width={800} height={600} />
2. Priority on too many images
Only the LCP image should have priority. Adding it to every image negates the benefit.
3. Missing sizes prop
Without sizes, responsive images default to the viewport width, causing unnecessarily large downloads.
4. Using img instead of Image
The native <img> tag gets none of the optimizations. Always use the Next.js Image component.
5. Enormous source images
Even with optimization, starting with a 5000x3000px image wastes processing time. Resize source images to max 2x the display size.
Image Formats
Next.js Image serves modern formats automatically:
| Format | Browser Support | Use Case |
|---|---|---|
| AVIF | Chrome, Firefox | Best compression, preferred |
| WebP | All modern browsers | Good compression, wide support |
| JPEG | Universal | Fallback |
The component negotiates the best format based on the browser's Accept header.
Quality Setting
Default quality is 75, which is fine for most images. Adjust for specific cases:
// High quality for hero images
<Image src="/hero.jpg" alt="" width={1200} height={600} quality={85} />
// Lower quality for thumbnails
<Image src="/thumb.jpg" alt="" width={200} height={200} quality={60} />
Measuring Performance
After implementing these optimizations, measure with:
- Lighthouse: Check LCP, CLS scores
- PageSpeed Insights: Real-world performance data
- Chrome DevTools Network tab: Verify image sizes and formats
- Web Vitals: Monitor in production with
@next/third-partiesor Vercel Analytics
Need Performance Optimization?
We optimize Next.js applications for Core Web Vitals across all our projects. Contact us if your site needs performance improvements.