Image Optimization (`next/image`)

Unoptimized images are the number one cause of slow performance, poor Core Web Vitals, and horrible user experience on the web. Standard HTML <img> tags force the browser to download a potentially massive 5MB photo just to display it as a tiny 200px thumbnail.

The `next/image` Component

Next.js solves this completely via the Image component. It automatically optimizes images on-demand.

import Image from 'next/image';

export default function Profile() {
  return (
    <Image
      src="/images/profile-photo.jpg" // Path from public/ dir
      alt="User Profile"
      width={400} // The width requested
      height={400} // The height requested
    />
  );
}

What does `next/image` do automatically?

  • Format Conversion: It converts old formats like JPEG or PNG into next-gen formats like WebP and AVIF automatically.
  • Resizing: It resizes the image down to the dimensions actually required by the user's screen (mobile vs desktop), saving megabytes of bandwidth.
  • Lazy Loading: Images are only loaded when they enter the user's viewport. An image halfway down the page won't be fetched until the user scrolls there.
  • Layout Shift Prevention: The component forces you to specify width/height (or a filling layout), preventing Cumulative Layout Shift (CLS) when images finally load.

Remote Images

If you want to optimize images hosted elsewhere (e.g. AWS S3, Cloudinary), you must explicitly allow those domains in your next.config.js file to protect your server from malicious actors exploiting your image processor.

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 's3.amazonaws.com',
      },
      {
        protocol: 'https',
        hostname: 'images.unsplash.com',
      },
    ],
  },
};

Fill Layout (Responsive Images)

If you don't know the exact width/height of an image (e.g., a fluid background banner), you can use the fill prop. The image will automatically expand to fill its parent container. The parent container MUST have position: relative applied to it!

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

Conclusion

Using `next/image` is almost mandatory for modern Next.js development and is essential for achieving a 100/100 Google Lighthouse score. Next, we will look at how Next.js optimizes Fonts.