Introduction
Website speed plays a big role in user experience, SEO ranking, and overall performance. Google Lighthouse measures how fast your application loads and gives insights about improvements. One of the most common issues developers face is unoptimized images, which negatively impact performance scores. Next.js provides powerful built‑in tools to automatically optimize images, reduce file sizes, and serve images in next‑gen formats. In this article, we will learn how to properly optimize images in Next.js and significantly improve your Lighthouse score using simple words and practical examples.
Why Image Optimization Matters for Next.js Apps
Images often take up the largest portion of a webpage’s size. Large or unoptimized images can slow down loading speed, affect Core Web Vitals, and decrease your SEO ranking.
Optimizing images helps you:
Improve Lighthouse and PageSpeed scores
Load pages faster on mobile and slow networks
Reduce data usage
Improve user experience
Increase conversion rates
Next.js solves these problems efficiently using the Image component.
Understanding the Next.js Image Component
The Next.js <Image /> component automatically optimizes images by:
Serving responsive images based on device screen size
Lazy‑loading images by default
Delivering modern formats like WebP
Compressing images without quality loss
Preventing layout shift using width and height attributes
Basic usage:
import Image from "next/image";
export default function Home() {
return (
<Image
src="/images/hero.jpg"
alt="Hero Banner"
width={1200}
height={600}
/>
);
}
This alone improves performance and layout stability.
Step 1: Use Correct Image Sizes (Avoid Oversized Images)
Many developers upload large images (like 3000px width) even when they are displayed at only 500px on the page. This wastes bandwidth.
Solution:
Example:
<Image
src="/images/product.jpg"
alt="Product"
width={800}
height={500}
sizes="(max-width: 600px) 100vw, 50vw"
/>
Next.js will generate optimized versions for each screen size.
Step 2: Use Lazy Loading for Better Performance
Next.js lazy‑loads images by default. This means images load only when they appear in the viewport, reducing initial load time.
To disable lazy loading (not recommended):
<Image src="/img.jpg" alt="Demo" loading="eager" />
Lazy loading improves Lighthouse Performance, especially LCP and FCP.
Step 3: Serve Images from a CDN or External Source
If your images are stored externally (like AWS S3 or Cloudinary), you must whitelist the domain in next.config.js.
Example:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'myimages.s3.amazonaws.com'
}
]
}
};
Next.js will then optimize external images automatically.
Step 4: Use Next.js Built‑in Image Optimization for WebP Format
WebP formats reduce image size by 25–35% without quality loss. Next.js automatically converts images to WebP when possible.
To explicitly allow formats:
module.exports = {
images: {
formats: ["image/webp", "image/avif"]
}
};
AVIF offers even better compression for modern browsers.
Step 5: Avoid Using <img> Tag (Unless Required)
Using the normal <img> tag bypasses Next.js optimization and lowers Lighthouse scores.
Bad example:
<img src="/images/banner.jpg" />
Better:
<Image src="/images/banner.jpg" alt="Banner" width={1200} height={600} />
Always use the <Image /> component for best performance.
Step 6: Improve Cumulative Layout Shift (CLS) Using Width & Height
Google Lighthouse heavily penalizes layout shift. To prevent this:
Example using fill:
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image src="/images/hero.jpg" alt="Hero" fill style={{ objectFit: 'cover' }} />
</div>
This prevents content from jumping around while the image loads.
Step 7: Use Next.js Image Loader for Custom Optimization
If you use Cloudinary, Imgix, or Akamai, you can set a custom loader.
Example for Cloudinary:
const cloudinaryLoader = ({ src, width, quality }) => {
return `https://res.cloudinary.com/mycloud/image/upload/w_${width},q_${quality || 75}/${src}`;
};
<Image
loader={cloudinaryLoader}
src="product.png"
width={800}
height={600}
alt="Product"
/>
This gives full control over image compression and delivery.
Step 8: Use Blur Placeholder for Better User Experience
The placeholder="blur" option provides a smooth loading effect.
Example:
<Image
src="/images/team.jpg"
alt="Team"
width={900}
height={600}
placeholder="blur"
blurDataURL="data:image/png;base64,iVBORw0KGgo..."
/>
This improves perceived performance and user experience.
Step 9: Compress Images Before Uploading
Even though Next.js optimizes images, manually compressing them helps even more.
Tools:
TinyPNG
Squoosh
Photoshop Export for Web
Aim to reduce image sizes by 30–60% before adding them to the project.
Step 10: Measure Performance with Lighthouse
Once optimization is complete:
Open Chrome DevTools
Go to Lighthouse tab
Run a performance audit
Check these metrics:
LCP (Largest Contentful Paint)
CLS (Cumulative Layout Shift)
FCP (First Contentful Paint)
TBT (Total Blocking Time)
You should see improved scores after implementing Next.js Image optimization steps.
Best Practices for Next.js Image Optimization
Always use the <Image /> component
Avoid serving raw images directly
Use responsive sizes (sizes attribute)
Preload important LCP images
Use CDN for image delivery
Serve next‑gen formats like WebP & AVIF
Reduce file size before uploading
These practices ensure strong SEO performance and better user experience on all devices.
Summary
Optimizing images in Next.js is one of the easiest and most impactful ways to improve Lighthouse performance. By using the built‑in Image component, configuring responsive sizes, enabling next‑gen formats, preventing layout shifts, and using CDNs or loaders, you can significantly boost your website’s loading speed and search ranking. Proper image optimization helps create a fast, modern, and SEO‑friendly Next.js application that performs well across all browsers and devices.