cd /news/developer-tools/next-image-deep-dive-optimization-la… · home topics developer-tools article
[ARTICLE · art-58750] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

next/image Deep Dive — Optimization, Lazy Loading, and the Props That Actually Matter

A developer's deep dive into Next.js's next/image component reveals that the `sizes` prop is the most underused optimization, capable of reducing image payload by 50-70% on mobile. The post explains how `priority`, `fill`, `quality`, and `remotePatterns` props affect performance and behavior, with practical patterns for common use cases.

read5 min views1 publishedJul 14, 2026

next/image

does a lot automatically — format conversion, lazy , preventing layout shift. But several props change behavior significantly, and getting them wrong either hurts performance or breaks things in production. Here's the complete picture of what actually matters, with the approach used in the image-heavy generation results interface.

When you use <Image>

from next/image

, you get automatically:

sizes

Prop — The Most Underused Optimization The sizes

prop tells the browser what size the image will be at different viewport widths. Without it, Next.js can't serve optimally-sized images and defaults to generating several sizes that may be larger than needed.

// Without sizes — Next.js doesn't know the display size
<Image src="/hero.jpg" alt="Hero" fill />

// With sizes — Next.js serves the right size for each viewport
<Image
  src="/hero.jpg"
  alt="Hero"
  fill
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>

Read the sizes

value as: "On mobile (under 768px), this image takes 100% of the viewport width. On tablets (under 1200px), 50%. On desktop, 33%."

Next.js uses this to calculate which image size to serve. Correct sizes

values can reduce image payload by 50-70% on mobile.

Common patterns:

// Full-width hero or banner
sizes="100vw"

// Half-width on desktop, full on mobile
sizes="(max-width: 768px) 100vw, 50vw"

// Card grid — 1 col mobile, 2 col tablet, 3 col desktop
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"

// Small thumbnail — always small
sizes="150px"

priority

— For Above-the-Fold Images By default, next/image

lazy loads everything. For images visible immediately on page load (hero images, header images, above-the-fold content), lazy is counterproductive — you want these to load as fast as possible.

// Hero image — load immediately, don't lazy load
<Image
  src="/hero.jpg"
  alt="Page hero"
  width={1200}
  height={600}
  priority
/>

Add priority

to the first image visible on page load. This tells Next.js to preload it and not apply lazy .

The rule: One or two images maximum per page should have priority

. If you add it to many images, you've eliminated the performance benefit of lazy .

fill

vs Width/Height — When to Use Each Explicit width/height: Use when you know the exact dimensions at render time. Generates precise sizes.

<Image
  src="/thumbnail.jpg"
  alt="Product thumbnail"
  width={300}
  height={200}
/>

** fill mode:** Use when the image should fill its container. The container must be

position: relative

(or absolute

or fixed

).

<div className="relative h-64 w-full">
  <Image
    src="/cover.jpg"
    alt="Article cover"
    fill
    sizes="100vw"
    className="object-cover"
  />
</div>

className="object-cover"

on the Image determines how it fills the container. object-cover

maintains aspect ratio and crops. object-contain

maintains aspect ratio with letterboxing.

quality

— When Default Isn't Right Default quality is 75, which is a good balance. For specific cases you might adjust:

// Photographic images — default 75 is fine
<Image src="/photo.jpg" alt="Photo" width={800} height={600} />

// Icons or images with sharp lines — higher quality prevents artifacts
<Image src="/logo.png" alt="Logo" width={100} height={50} quality={90} />

// Background textures where quality difference isn't visible
<Image src="/texture.jpg" alt="" width={1200} height={800} quality={60} />

Higher quality = larger file size. The default is right for most cases.

remotePatterns

Config By default, next/image

only optimizes images from your own domain. For external images, you need to configure allowed patterns:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        port: '',
        pathname: '/images/**',
      },
      {
        protocol: 'https',
        hostname: '*.cdn-example.com', // wildcard subdomain
      },
    ],
  },
};

module.exports = nextConfig;

Be specific with pathname

patterns. Wildcard /**

allows any path on that host. More restrictive patterns are safer.

placeholder

Prop — Blur-Up For a smooth experience, next/image

supports a blur placeholder that shows while the full image loads:

// Static images — Next.js generates blurDataURL automatically at build time
import heroImage from '/public/hero.jpg';

<Image
  src={heroImage}
  alt="Hero"
  placeholder="blur"
  priority
/>

For dynamic images (external URLs), you need to provide the blur data yourself:

// Generate a tiny blurred placeholder (many services provide these)
const blurDataURL = 'data:image/jpeg;base64,/9j/4AAQ...'; // tiny base64 image

<Image
  src={dynamicImageUrl}
  alt="Dynamic image"
  width={800}
  height={600}
  placeholder="blur"
  blurDataURL={blurDataURL}
/>

The placeholder="blur"

approach significantly improves perceived performance for above-the-fold images.

To verify your image optimization is working:

Img

Type

column — should show webp

or avif

instead of jpeg

/png

Size

column vs original file size A well-optimized image should be significantly smaller than the original and in a modern format.Forgetting sizes on fill images. Without

sizes

, Next.js can't optimize for viewport — generates full-size images for all viewports.Adding priority to too many images. It's for above-the-fold only. One or two per page maximum.

Not configuring remotePatterns. External images without pattern configuration fall back to unoptimized serving, breaking the performance benefits.

Using <img> instead of <Image>. Native

<img>

tags don't get any next/image optimization — no format conversion, no lazy , no layout stability. ESLint rule next/no-img-element

catches this.| Prop | When to use | |---|---| sizes | Always, when using fill or when image width changes across viewports | priority | First 1-2 visible images on page load only | fill | When image should fill a container with unknown dimensions | quality | When default 75 is visibly too low (icons) or unnecessarily high | placeholder="blur" | Above-the-fold images where is visible to users |

The three that move the needle most: correct sizes

(biggest file size impact), priority

on LCP images (biggest perceived performance impact), and remotePatterns

configuration (required for external images to optimize at all).

If you serve images from a custom CDN with its own optimization parameters, you can configure a custom :

// next.config.js
module.exports = {
  images: {
    : 'custom',
    File: './image.js',
  },
};
// image.js
export default function myImage({ src, width, quality }) {
  return `https://your-cdn.com/image?url=${src}&w=${width}&q=${quality || 75}`;
}

This gives you full control over how image URLs are constructed for optimization, useful when your CDN uses different query parameter formats than Next.js expects.

For most applications using standard hosting, the default is correct. Custom s are for specific CDN integrations that need URL format control.

If you're on an older Next.js version using domains

config, migrate to remotePatterns

:

// Old (deprecated)
images: {
  domains: ['cdn.example.com'],
}

// New (use this)
images: {
  remotePatterns: [
    { protocol: 'https', hostname: 'cdn.example.com' }
  ],
}

remotePatterns

is more secure — it supports pathname restrictions that domains

doesn't, preventing a compromised external hostname from serving arbitrary paths through your Next.js image optimizer.

── more in #developer-tools 4 stories · sorted by recency
── more on @next.js 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/next-image-deep-dive…] indexed:0 read:5min 2026-07-14 ·