easyFrontend EngineerMedia
How does Next.js image optimization work, and what are the performance best practices for loading images?
Posted 18/04/2026
by Mehedy Hasan Ador
Question Details
At a media company interview:
> "Our landing page loads 15 high-resolution images and gets a 35 Lighthouse performance score. How would you optimize this using Next.js?"
> "Our landing page loads 15 high-resolution images and gets a 35 Lighthouse performance score. How would you optimize this using Next.js?"
Suggested Solution
Next.js Image Component
import Image from "next/image";
// ✅ Optimized
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // Preload above-the-fold images
placeholder="blur" // Show blur placeholder while loading
quality={85} // Default is 75, max 100
/>
// ✅ Remote image
<Image
src="https://cdn.example.com/photo.jpg"
alt="Product"
width={800}
height={600}
sizes="(max-width: 768px) 100vw, 50vw" // Hint for responsive loading
/>
What Next.js Does Automatically
1. Format conversion → WebP/AVIF (30-50% smaller than JPEG)2. Responsive srcset → Generates multiple sizes (640w, 750w, 828w, etc.)
3. Lazy loading → Images below fold load on viewport entry
4. Blur placeholder → Low-res SVG/blur while full image loads
5. Cache headers →
Cache-Control: public, max-age=31536000, immutablePerformance Best Practices
1. Use sizes for Responsive Images
<Image
src={product.image}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
// Without this, browser may download the largest size
/>
2. Priority for Above-the-Fold
<Image src="/hero.jpg" priority /> // Adds <link rel="preload">
// Without priority, LCP (Largest Contentful Paint) suffers
3. Blur Placeholder
// Static import auto-generates blur
import heroBlur from "@/public/hero.jpg";
<Image src={heroBlur} placeholder="blur" />
// Dynamic: provide blurDataURL
<Image src={url} placeholder="blur" blurDataURL={shimmer(700, 475)} />
4. Fill Mode for Flexible Containers
<div className="relative aspect-video">
<Image src="/video-thumb.jpg" fill className="object-cover" />
</div>
// No width/height needed, fills parent container
Configuration
// next.config.ts
const config = {
images: {
formats: ['image/avif', 'image/webp'],
remotePatterns: [
{ protocol: 'https', hostname: 'cdn.example.com' },
],
deviceSizes: [640, 750, 828, 1080, 1200, 1920],
},
};
Lighthouse Score Impact
<img>)priority on herosizes attribute