How to Optimize Images in Next.js for Performance
  Images often account for 50-70% of a webpage’s total size, directly impacting Core Web Vitals metrics like Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS). Poor image handling can tank your Lighthouse scores, increase bounce rates, and hurt SEO rankings—even if your JavaScript is perfectly optimized.
This guide covers Next.js image optimization using the built-in next/image component, from basic implementation to advanced CDN integration and caching strategies. You’ll learn how to deliver responsive, fast-loading images that improve both performance metrics and user experience.
Key Takeaways
- The 
next/imagecomponent automatically converts images to modern formats like WebP and AVIF, reducing file sizes by 25-35% - Proper image optimization can improve LCP by 50% and reduce bandwidth costs by 60%
 - Using the 
priorityprop on above-the-fold images and configuring responsive sizes prevents layout shifts - Custom loaders enable integration with specialized image CDNs for high-traffic applications
 
Why the next/image Component Matters for Performance
The next/image component isn’t just a wrapper around HTML’s <img> tag—it’s an automated optimization pipeline that handles the heavy lifting of modern image delivery.
Core Performance Features
Automatic format conversion: Next.js serves WebP and AVIF formats when browsers support them, reducing file sizes by 25-35% compared to JPEG/PNG without quality loss.
Responsive image generation: The component creates multiple image sizes at build time or on-demand, ensuring mobile users don’t download desktop-sized images.
Built-in lazy loading: Images below the fold load only when users scroll near them, reducing initial page weight and improving First Contentful Paint (FCP).
Layout shift prevention: By requiring width and height props (or using the fill prop), the component reserves space before images load, eliminating CLS issues.
Basic Implementation and Essential Props
Start with a simple implementation that covers 80% of use cases:
import Image from 'next/image'
export default function Hero() {
  return (
    <Image
      src="/hero-banner.jpg"
      alt="Product showcase"
      width={1200}
      height={600}
      priority // Load immediately for LCP optimization
    />
  )
}
When to Use Key Props
priority: Add this to above-the-fold images that affect LCP. It disables lazy loading and adds a preload link. Use sparingly—only for 1-2 critical images per page.
sizes: Essential for responsive images. Tells the browser which image size to download based on viewport width:
<Image
  src="/product.jpg"
  alt="Product"
  width={800}
  height={600}
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 800px"
/>
placeholder=“blur”: Displays a low-quality placeholder while the main image loads. For static imports, Next.js generates the blurDataURL automatically:
import heroImage from '@/public/hero.jpg'
<Image
  src={heroImage}
  alt="Hero"
  placeholder="blur"
  // blurDataURL generated automatically for static imports
/>
Configuring Remote Images with remotePatterns
For images from external sources, configure remotePatterns in next.config.js (the older domains setting is deprecated):
// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
    ],
  },
}
This security feature prevents malicious image requests while allowing specific external sources.
Discover how at OpenReplay.com.
Advanced Optimization with CDNs and Custom Loaders
For high-traffic applications, integrate specialized image CDNs like Cloudinary or Imgix using custom loaders:
// lib/imageLoader.js
export default function cloudinaryLoader({ src, width, quality }) {
  const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
  return `https://res.cloudinary.com/demo/image/upload/${params.join(',')}/${src}`
}
// Component usage
<Image
  loader={cloudinaryLoader}
  src="product.jpg"
  alt="Product"
  width={400}
  height={300}
/>
Caching Strategy for Optimal Performance
Next.js sets aggressive cache headers by default:
Cache-Control: public, max-age=31536000, immutable
For dynamic content, override these in next.config.js:
module.exports = {
  async headers() {
    return [
      {
        source: '/_next/image(.*)',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=86400, stale-while-revalidate=604800',
          },
        ],
      },
    ]
  },
}
Best Practices for Production
Measure impact with real data: Use Lighthouse and WebPageTest to track LCP improvements. A properly optimized hero image can reduce LCP by 1-2 seconds.
Balance quality and file size: Set quality={75} as a starting point. Test visual quality against file size savings—dropping from 100 to 75 often saves 40% with minimal visual impact.
Handle different image types appropriately: Use unoptimized for SVGs and already-optimized assets:
<Image
  src="/logo.svg"
  alt="Logo"
  width={200}
  height={50}
  unoptimized
/>
TypeScript for type safety: Import images for automatic dimension detection and type checking:
import type { StaticImageData } from 'next/image'
import productImage from '@/public/product.jpg'
interface ProductCardProps {
  image: StaticImageData
  alt: string
}
Common Troubleshooting Issues
“Invalid src prop” error: Ensure remote domains are configured in remotePatterns or use a custom loader.
Blurry images on high-DPI displays: Check that source images are at least 2x the display size and avoid aggressive quality settings below 70.
Build time increases: For sites with hundreds of images, consider using on-demand optimization instead of build-time processing, or implement a custom loader with an external service.
Conclusion
Next.js image optimization through the next/image component provides immediate performance wins with minimal configuration. Start with the basics—proper sizing, lazy loading, and format conversion—then layer in advanced techniques like CDN integration and custom loaders as your traffic scales.
The key is measuring real-world impact: properly optimized images can improve LCP by 50%, reduce bandwidth costs by 60%, and significantly boost your Core Web Vitals scores. Focus on your above-the-fold images first, then systematically optimize the rest of your image pipeline.
FAQs
No, you must configure allowed domains in next.config.js using remotePatterns for security. This prevents malicious actors from using your application as an image proxy. You can also bypass this with custom loaders.
Source images should be at least 2x the display size for high-DPI screens. Also check your quality setting isn't too low. A quality of 75-85 usually provides the best balance between file size and visual clarity.
No, use priority only for 1-2 critical above-the-fold images that affect LCP. Overusing it defeats the purpose of lazy loading and can actually hurt performance by loading too many images simultaneously.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.