intermediate Step 10 of 15

Image Optimization

Next.js Development

Image Optimization with next/image

Images typically account for the largest share of page weight on the web, directly impacting load times, bandwidth usage, and Core Web Vitals scores. Next.js provides the next/image component that automatically optimizes images on demand: resizing, converting to modern formats like WebP and AVIF, lazy loading below the fold, and preventing Cumulative Layout Shift with automatic dimension calculation. Using next/image instead of plain <img> tags can dramatically improve your site's performance without manual image processing pipelines.

Basic Usage

The Image component requires width and height props (or the fill prop) to prevent layout shift. Next.js uses these dimensions to calculate the correct aspect ratio and reserve space before the image loads.

import Image from "next/image";

// Local image (imported — dimensions are known at build time)
import heroImage from "@/public/hero.jpg";

export default function Hero() {
  return (
    <section>
      {/* Local image with automatic optimization */}
      <Image
        src={heroImage}
        alt="Hero banner showing our product"
        priority  // Load immediately (above the fold)
        placeholder="blur"  // Show blur while loading
      />

      {/* Remote image with explicit dimensions */}
      <Image
        src="https://images.unsplash.com/photo-example"
        alt="Nature landscape"
        width={800}
        height={600}
        quality={85}
      />

      {/* Sized image */}
      <Image
        src="/logo.png"
        alt="Company logo"
        width={200}
        height={50}
      />
    </section>
  );
}

Fill Mode for Responsive Images

The fill prop makes the image fill its parent container, useful for hero images, backgrounds, and flexible layouts. The parent must have position: relative.

import Image from "next/image";

function ProductCard({ product }: { product: { name: string; image: string } }) {
  return (
    <div className="product-card">
      {/* Parent must be position: relative with defined dimensions */}
      <div style={{ position: "relative", width: "100%", height: "300px" }}>
        <Image
          src={product.image}
          alt={product.name}
          fill
          sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
          style={{ objectFit: "cover" }}
        />
      </div>
      <h3>{product.name}</h3>
    </div>
  );
}

// With Tailwind CSS
function GalleryImage({ src, alt }: { src: string; alt: string }) {
  return (
    <div className="relative aspect-square">
      <Image
        src={src}
        alt={alt}
        fill
        className="object-cover rounded-lg"
        sizes="(max-width: 768px) 50vw, 25vw"
      />
    </div>
  );
}

Configuring Remote Images

To use images from external domains, configure allowed domains in next.config.js.

// next.config.js
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "images.unsplash.com",
      },
      {
        protocol: "https",
        hostname: "cdn.example.com",
        pathname: "/images/**",
      },
      {
        protocol: "https",
        hostname: "*.amazonaws.com",
      },
    ],
    // Image formats to serve (WebP is default, AVIF for better compression)
    formats: ["image/avif", "image/webp"],
    // Device sizes for responsive images
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
  },
};

module.exports = nextConfig;

Performance Best Practices

import Image from "next/image";

function OptimizedPage() {
  return (
    <div>
      {/* 1. Use priority for above-the-fold images (LCP) */}
      <Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority />

      {/* 2. Always provide sizes for responsive images */}
      <Image
        src="/product.jpg"
        alt="Product"
        width={400}
        height={300}
        sizes="(max-width: 768px) 100vw, 400px"
      />

      {/* 3. Use placeholder="blur" for better perceived performance */}
      <Image
        src={localImage}
        alt="Blurred placeholder"
        placeholder="blur"
      />

      {/* 4. Adjust quality for file size vs visual quality trade-off */}
      <Image
        src="/photo.jpg"
        alt="Photo"
        width={800}
        height={600}
        quality={75}  // Default is 75. Lower = smaller files
      />
    </div>
  );
}
Tip: Always set the sizes prop on responsive images. Without it, Next.js defaults to generating images for all device sizes, which wastes bandwidth. The sizes prop tells the browser how wide the image will be at different viewport widths, allowing it to download the smallest appropriate image.

Key Takeaways

  • next/image automatically optimizes images with resizing, format conversion, and lazy loading.
  • Use priority for above-the-fold images to improve Largest Contentful Paint (LCP).
  • The fill prop makes images fill their parent container for responsive layouts.
  • Configure remotePatterns in next.config.js to allow external image domains.
  • Always provide the sizes prop for responsive images to optimize download sizes.