DEV Community

Cover image for Next.js Image Optimization: next/image Deep Dive for Production Apps
Aon infotech
Aon infotech

Posted on

Next.js Image Optimization: next/image Deep Dive for Production Apps

Images consistently account for 50–70% of total page weight in most web applications. Next.js ships a built-in next/image component that handles the heavy lifting automatically — but using it correctly means understanding what it actually does, what configuration matters in production, and where the defaults fall short.

What next/image Actually Does

When you use next/image, requests go through Next.js's image optimization API at /_next/image. On each request it:

  • Converts to WebP or AVIF (significantly smaller than JPEG/PNG)
  • Resizes to the requested display dimensions
  • Lazy loads by default
  • Reserves layout space to prevent Cumulative Layout Shift
  • Caches the optimized output server-side Self-hosted deployments need sharp for server-side optimization:
npm install sharp
Enter fullscreen mode Exit fullscreen mode

On Vercel, optimization runs at the edge automatically.

Basic Implementation

import Image from 'next/image'
import heroImage from '@/public/hero.jpg'

// Local image — dimensions extracted at build time
export function Hero() {
  return (
    <Image
      src={heroImage}
      alt="Descriptive alt text here"
      priority
    />
  )
}

// Remote image — must specify dimensions
export function ProductCard({ imageUrl }) {
  return (
    <Image
      src={imageUrl}
      alt="Product"
      width={400}
      height={300}
      sizes="(max-width: 768px) 100vw, 400px"
    />
  )
}
Enter fullscreen mode Exit fullscreen mode

The sizes Prop — Most Commonly Misused

Without sizes, Next.js generates a single large image. With it, the browser receives multiple sizes and selects the correct one for the current viewport.

// Wrong — browser downloads large image regardless of display size
<Image src={src} alt={alt} width={800} height={600} />

// Correct — sizes match actual CSS rendering
<Image
  src={src}
  alt={alt}
  width={800}
  height={600}
  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 800px"
/>
Enter fullscreen mode Exit fullscreen mode

The sizes string describes your CSS layout. If the image is full-width on mobile, half-width on tablet, and 800px fixed on desktop, write exactly that.

fill for Flexible Containers

When you don't know dimensions ahead of time:

<div className="relative h-64 w-full">
  <Image
    src={imageUrl}
    alt="Cover"
    fill
    className="object-cover"
    sizes="(max-width: 768px) 100vw, 50vw"
  />
</div>
Enter fullscreen mode Exit fullscreen mode

The parent needs position: relative and defined dimensions. fill makes the image absolutely positioned to match the parent.

Priority Loading for LCP

The Largest Contentful Paint image should never be lazy loaded:

// Any image visible on page load — hero, banner, above-fold card
<Image
  src={heroSrc}
  alt="Hero"
  fill
  priority
  sizes="100vw"
/>
Enter fullscreen mode Exit fullscreen mode

priority adds a preload link and disables lazy loading. Don't add it to off-screen images — that wastes bandwidth on content users may not scroll to.

Remote Domains Configuration

Next.js blocks external images by default. Configure remotePatterns in next.config.js:

module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.example.com',
        pathname: '/uploads/**',
      },
      {
        protocol: 'https',
        hostname: '**.cloudinary.com', // wildcard subdomain
      },
    ],
  },
}
Enter fullscreen mode Exit fullscreen mode

Use remotePatterns over the deprecated domains array — it gives you path-level control.

Quality, Format, and Cache Configuration

module.exports = {
  images: {
    quality: 80,                    // default 75 — increase for sharper images
    formats: ['image/avif', 'image/webp'], // AVIF first, WebP fallback
    deviceSizes: [640, 750, 828, 1080, 1200, 1920],
    minimumCacheTTL: 60 * 60 * 24, // cache for 24h instead of default 60s
  },
}
Enter fullscreen mode Exit fullscreen mode

AVIF compresses better than WebP but encodes slower. Browser negotiation handles the format selection — keep both in the array.

Blur Placeholder

// Local image — blur data generated at build time automatically
<Image
  src={productImage}
  alt="Product"
  placeholder="blur"
/>

// Remote image — provide base64 blurDataURL
<Image
  src={remoteUrl}
  alt="Product"
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQ..."
  width={800}
  height={600}
/>
Enter fullscreen mode Exit fullscreen mode

The blur shows immediately while the full image loads. Perceived performance improves significantly even when actual load time stays the same.

Production Gotchas

Sharp is not optional for self-hosted apps. Without it, Next.js falls back to a slower path or disables optimization entirely.

Memory watch on high-traffic sites. Each unique URL/size combination gets cached. Applications serving user-uploaded images with unique filenames can exhaust cache memory. Set a reasonable minimumCacheTTL and monitor.

SVGs bypass the optimizer. SVG files are served as-is — the optimizer is designed for raster images. Handle SVGs with SVGR or as static assets.

Build-time vs request-time dimensions. Local imports have their dimensions extracted at build time. Remote URLs need width and height specified in the component or fill layout.

Measuring the Impact

Track these before and after switching to next/image:

  • LCP score in Core Web Vitals (primary image performance metric)
  • Total image transfer size in DevTools Network tab filtered by Img
  • CLS score — proper dimension reservation eliminates most image-related layout shift For most apps serving photographic content, correctly configured next/image reduces image payload by 50–70% and brings CLS to near zero.

For AI-generated imagery like the content at Pixova's free sketch generator, the WebP conversion from PNG source files typically produces 40–60% size reduction — meaningful at scale when thousands of users are loading AI-generated images daily.

Top comments (0)