Optimizing Images in Next.js: The Complete Guide
Images often make up the largest portion of a webpage's size, which is why image optimization is crucial for performance. Next.js provides built-in image optimization through its next/image
component.
Why Optimize Images?
Properly optimized images can significantly improve:
- Loading performance
- Core Web Vitals metrics (particularly Largest Contentful Paint)
- Data usage for users on limited data plans
- Overall user experience
The Next.js Image Component
Next.js provides the Image
component as a replacement for the standard HTML <img>
tag:
import Image from "next/image";
function MyComponent() {
return (
<Image
src="/my-image.jpg"
alt="My optimized image"
width={600}
height={400}
priority={false}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j..." // Optional blur placeholder
/>
);
}
Key Features of next/image
1. Automatic Optimization
The Image component automatically:
- Resizes images to avoid shipping large images to small screens
- Converts images to modern formats like WebP and AVIF when the browser supports them
- Lazy loads images by default (loading them only when they enter the viewport)
2. Preventing Cumulative Layout Shift (CLS)
By requiring width
and height
props (or using fill
), Next.js prevents layout shift as images load.
3. Responsive Images
The Image component generates multiple sizes of each image for different devices using the sizes
prop:
<Image
src="/hero.jpg"
alt="Hero image"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
fill
className="object-cover"
/>
Image Optimization Options
Local Images
With local images, you can import them directly:
import heroImage from "@/public/hero.jpg";
// Next.js automatically determines the width and height
<Image src={heroImage} alt="Hero" placeholder="blur" />
Remote Images
For remote images, you must provide the dimensions and configure domains in next.config.js
:
// next.config.js
module.exports = {
images: {
domains: ["example.com"],
// Or, more safely, use remotePatterns
remotePatterns: [
{
protocol: "https",
hostname: "example.com",
port: "",
pathname: "/images/**",
},
],
},
};
Advanced Techniques
1. Art Direction with Different Image Ratios
Sometimes you need different image crops for different screen sizes:
import Image from "next/image";
function ResponsiveArt() {
return (
<>
<Image
src="/desktop.jpg"
alt="Desktop version"
width={1920}
height={1080}
className="hidden md:block"
/>
<Image
src="/mobile.jpg"
alt="Mobile version"
width={800}
height={1200}
className="block md:hidden"
/>
</>
);
}
2. Custom Image Loaders
You can use different image optimization providers like Cloudinary or Imgix:
// next.config.js
module.exports = {
images: {
loader: "cloudinary",
path: "https://res.cloudinary.com/your-account/",
},
};
3. Priority Images
For images that are in the viewport on page load (like hero images), use the priority prop to preload them:
<Image
src="/hero.jpg"
alt="Hero"
width={2000}
height={1000}
priority
/>
Best Practices
- Always use
alt
text for accessibility - Set
priority
for LCP images (usually hero images) - Use the right image format (WebP for photos, SVG for icons and illustrations)
- Size images appropriately - don't use larger dimensions than needed
- Use responsive sizing with
sizes
to adapt to different viewports - Consider blur placeholders for large images to improve perceived performance
Conclusion
Next.js's Image component takes the pain out of implementing image optimization best practices. By default, it provides significant performance improvements over standard <img>
tags, making your site faster and providing a better user experience. Remember that optimizing images is one of the easiest ways to improve your site's performance metrics and user satisfaction.