Skip to main content
Ganesh Joshi
Back to Blogs

Next.js Image: optimization, sizes, and AVIF

February 15, 20265 min read
Tutorials
Color palette and image design on screen

Images are often the largest assets on a webpage and the main factor in Largest Contentful Paint (LCP). The Next.js Image component handles optimization automatically: it resizes images, serves modern formats, lazy loads by default, and prevents layout shift. Using it correctly can significantly improve Core Web Vitals.

How next/image works

When you use the Image component, Next.js:

  1. Generates multiple sizes of the image at build time or on-demand
  2. Serves WebP or AVIF when the browser supports them
  3. Lazy loads images below the fold
  4. Reserves space to prevent Cumulative Layout Shift (CLS)
Feature Benefit
Automatic resizing Smaller file sizes for smaller screens
Modern formats WebP is 25-35% smaller than JPEG; AVIF even smaller
Lazy loading Images load only when approaching viewport
Aspect ratio reservation No layout shift as images load

Basic usage

Import the component and provide required props:

import Image from 'next/image';

export default function Hero() {
  return (
    <Image
      src="/hero.jpg"
      alt="Hero image showing a mountain landscape"
      width={1200}
      height={630}
    />
  );
}

For local images, you can import them directly:

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

export default function Hero() {
  return (
    <Image
      src={heroImage}
      alt="Hero image"
      // width and height are inferred from the import
    />
  );
}

Remote images

For external images, add the domain to next.config.js:

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.unsplash.com',
      },
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
    ],
  },
};

Then use the full URL:

<Image
  src="https://images.unsplash.com/photo-123"
  alt="Unsplash photo"
  width={800}
  height={600}
/>

The sizes prop

The sizes prop tells the browser how wide the image will be at different viewport widths. Without it, Next.js may generate and serve larger images than needed.

Common patterns

Layout sizes value
Full-width hero 100vw
Half-width on desktop (min-width: 768px) 50vw, 100vw
Fixed max-width card (max-width: 768px) 100vw, 400px
Sidebar thumbnail 200px

Full example

<Image
  src="/product.jpg"
  alt="Product photo"
  width={800}
  height={800}
  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 400px"
/>

This tells the browser:

  • On screens up to 640px: image is 100% of viewport width
  • On screens 641px to 1024px: image is 50% of viewport width
  • On larger screens: image is 400px wide

The browser picks the smallest source that fits, reducing bandwidth.

Fill mode

For responsive images that fill their container, use fill instead of width/height:

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

The parent must have position: relative (or absolute/fixed). The image fills the parent and you control fit with object-fit.

Priority and LCP

For the most important image on the page (usually the LCP element), add priority:

<Image
  src="/hero.jpg"
  alt="Hero"
  width={1920}
  height={1080}
  priority
  sizes="100vw"
/>

Priority:

  • Disables lazy loading
  • Adds a preload hint in the HTML head
  • Ensures the image loads as fast as possible

Use priority on 1-2 images per page. Overusing it defeats the purpose and can hurt performance.

Blur placeholders

Placeholders improve perceived performance by showing something immediately while the full image loads.

Local images

For imported local images, Next.js generates blur data automatically:

import Image from 'next/image';
import photo from '@/public/photo.jpg';

<Image
  src={photo}
  alt="Photo"
  placeholder="blur"
  // blurDataURL is generated automatically
/>

Remote images

For remote images, provide your own blur data URL:

<Image
  src="https://cdn.example.com/photo.jpg"
  alt="Photo"
  width={800}
  height={600}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
/>

Generate blur hashes with tools like plaiceholder or a simple 10x10 resized version encoded as base64.

Quality setting

The default quality is 75, which balances file size and visual quality. Adjust per image:

<Image
  src="/photo.jpg"
  alt="High quality photo"
  width={1200}
  height={800}
  quality={85}
/>
Quality Use case
60-70 Thumbnails, decorative images
75 Default, good for most images
80-85 Hero images, product photos
90+ Photography portfolios, print-quality

Higher quality means larger files. Rarely go above 90.

Image formats

Next.js serves WebP by default when supported. You can enable AVIF:

// next.config.js
module.exports = {
  images: {
    formats: ['image/avif', 'image/webp'],
  },
};

AVIF offers better compression but takes longer to encode. For static sites with build-time optimization, this tradeoff is often worth it.

Responsive images with art direction

For different images at different breakpoints (not just sizes), use the <picture> element with regular <source> elements and an <img> fallback. Next.js Image handles one source; for art direction, you need native HTML:

<picture>
  <source
    media="(min-width: 768px)"
    srcSet="/hero-desktop.jpg"
  />
  <source
    media="(min-width: 480px)"
    srcSet="/hero-tablet.jpg"
  />
  <img
    src="/hero-mobile.jpg"
    alt="Hero"
    width={480}
    height={320}
  />
</picture>

For most responsive needs, sizes with a single source is sufficient.

Common mistakes

Mistake Fix
Missing alt Always provide descriptive alt text
Missing sizes Set sizes to match actual rendered width
Priority on all images Use only for above-fold LCP image
Wrong width/height Use actual or desired display dimensions
fill without parent positioning Parent needs position: relative
Huge quality values Keep at 75-85 for most images

Debugging image optimization

Check which image variant loads in DevTools Network tab. The URL includes size and format info:

/_next/image?url=%2Fhero.jpg&w=1920&q=75

Compare file sizes to verify optimization is working. WebP should be noticeably smaller than JPEG.

Static export limitations

If you use output: 'export' for static HTML, Next.js image optimization requires a server. Options:

  • Use a third-party image CDN (Cloudinary, Imgix)
  • Use unoptimized: true on images (loses optimization)
  • Deploy to a platform with image optimization (Vercel, Netlify)

Summary

The Next.js Image component automates image optimization with minimal configuration. Set sizes to match your layout, use priority for above-fold images, add placeholder="blur" for better perceived performance, and let Next.js handle resizing and format conversion. This combination typically reduces image weight by 40-60% and improves LCP scores significantly.

Frequently Asked Questions

The next/image component automatically resizes images to multiple sizes, converts to modern formats like WebP and AVIF, lazy loads images by default, and prevents layout shift with reserved space.

Add the external domain to images.remotePatterns in next.config.js. Specify the protocol, hostname, and optionally pathname patterns. Without this, Next.js blocks external images for security.

Set sizes to match how wide the image displays at different breakpoints. For full-width images use 100vw. For a 400px max-width card use (max-width: 768px) 100vw, 400px. Correct sizes prevent downloading oversized images.

Use priority on the largest image above the fold, typically the hero image or LCP element. It disables lazy loading and preloads the image. Use it on 1-2 images per page, not every image.

For local images, import them and Next.js generates blur data automatically. For remote images, set placeholder='blur' and provide a blurDataURL with a small base64-encoded preview image.

Related Posts