If you’ve ever run a Lighthouse audit on a Next.js site, you’ve likely seen the dreaded ‘Efficiently encode images’ or ‘Largest Contentful Paint image was slowly loaded’ warnings. In my experience, images are almost always the primary culprit behind sluggish page loads. That’s why I’ve put together this next.js image component optimization tutorial to help you move beyond the standard <img> tag and start leveraging the powerful next/image component.

The next/image component isn’t just a wrapper; it’s a sophisticated image orchestration tool that handles resizing, optimization, and serving images in modern formats like WebP and AVIF automatically. When combined with a strategy for introduction to image lazy loading, you can drastically reduce your page weight.

Prerequisites

Step 1: Switching to the Image Component

The first step is replacing all your standard HTML <img> tags with the Next.js Image component. The most critical difference is that Next.js requires you to define the width and height to prevent Layout Shift (CLS).

import Image from 'next/image'
import profilePic from '../public/me.png'

export default function Page() {
  return (
    <Image
      src={profilePic}
      alt="Author profile picture"
      width={500}
      height={500}
      placeholder="blur"
    />
  )
}

When you import a local image, Next.js automatically calculates the width and height, but for remote images, you must provide them manually or use the fill property.

Step 2: Handling Remote Images and Domains

I’ve found that many developers struggle when they first try to fetch images from a CMS or S3 bucket. For security, Next.js requires you to whitelist external domains in your next.config.js file. Without this, your build will fail.

// next.config.js
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.unsplash.com',
        port: '',
        pathname: '/photo/**',
      },
    ],
  },
}

module.exports = nextConfig

As shown in the image below, the correct configuration ensures that the Next.js server can proxy and optimize the remote asset before delivering it to the client.

Next.js config file showing the remotePatterns configuration for external images
Next.js config file showing the remotePatterns configuration for external images

Step 3: Implementing the ‘Fill’ Layout for Responsive Design

In modern web design, we rarely know the exact dimensions of an image. I prefer using the fill prop combined with a parent container that has position: relative. This allows the image to act like a background image while remaining fully optimized.

<div style={{ position: 'relative', width: '100%', height: '400px' }}>
  <Image
    src="/hero-banner.jpg"
    alt="Hero Banner"
    fill
    style={{ objectFit: 'cover' }}
    priority
  />
</div>

Note the priority prop here. This is a game-changer for LCP. By adding priority, you tell Next.js to preload this image, which is essential for any image appearing above the fold.

Step 4: Advanced Optimization with Sizes and Quality

By default, Next.js serves an optimized version of the image, but you can fine-tune this. The sizes attribute is the most underutilized tool in this next.js image component optimization tutorial. It tells the browser exactly how wide the image will be at different breakpoints, preventing the browser from downloading a 2000px image for a 300px mobile screen.

<Image
  src="/product.jpg"
  alt="Product"
  fill
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
  quality={75}
/>

I typically set quality={75} because the visual difference between 75 and 100 is negligible, but the file size difference is massive. For an even more comprehensive performance boost, you should also look into how to reduce unused javascript in next.js to ensure your scripts aren’t blocking the image render.

Pro Tips for Production

Troubleshooting Common Issues

Image is distorted or stretched

This usually happens when using fill without object-fit: cover or contain in your CSS. Always define how the image should behave within its bounding box.

“Invalid src prop” Error

Double-check your remotePatterns in next.config.js. Remember that a trailing slash or a missing protocol (https) can cause this error.

What’s Next?

Now that your images are optimized, it’s time to look at the rest of your critical rendering path. I recommend auditing your bundle size and ensuring your fonts are preloaded. If you’re building a content-heavy site, consider implementing a dedicated Image CDN like Cloudinary or Imgix, which Next.js integrates with seamlessly via custom loaders.