Skip to main content
Back to Blog
Tutorials
3 min read
November 10, 2024

How to Optimize Images in Next.js for Core Web Vitals

Learn how to use the Next.js Image component correctly to improve LCP, prevent CLS, and serve modern formats. Covers responsive images, blur placeholders, and priority loading.

Ryel Banfield

Founder & Lead Developer

Images are the largest element on most web pages. They directly impact your Largest Contentful Paint (LCP) score and can cause Cumulative Layout Shift (CLS) if not handled correctly. Next.js provides an Image component that handles most optimization automatically.

The Next.js Image Component

import Image from "next/image";

<Image
  src="/images/hero.jpg"
  alt="Hero banner showing a modern office"
  width={1200}
  height={600}
  priority
/>

This automatically:

  • Serves WebP/AVIF format when supported
  • Generates responsive sizes
  • Lazy loads images below the fold
  • Prevents CLS with width/height
  • Optimizes quality

Priority Loading for LCP

The hero image or above-the-fold image should use the priority prop:

<Image
  src="/images/hero.jpg"
  alt="Hero image"
  width={1200}
  height={600}
  priority // Preloads this image
/>

priority adds a <link rel="preload"> tag to the document head, telling the browser to fetch this image immediately. Only use it for the LCP element β€” typically the hero image.

Responsive Images with sizes

The sizes prop tells the browser how wide the image will be at different viewport widths:

<Image
  src="/images/feature.jpg"
  alt="Feature screenshot"
  width={800}
  height={500}
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>

This means:

  • On mobile (up to 768px): the image is full viewport width
  • On tablet (up to 1200px): the image is 50% viewport width
  • On desktop: the image is 33% viewport width

Without sizes, the browser downloads the largest image for every viewport. With proper sizes, mobile users download smaller files.

Fill Mode for Dynamic Sizes

When you do not know the image dimensions ahead of time, use fill:

<div className="relative h-64 w-full">
  <Image
    src="/images/card-image.jpg"
    alt="Card image"
    fill
    className="object-cover"
    sizes="(max-width: 768px) 100vw, 50vw"
  />
</div>

The parent must have position: relative and defined dimensions. The image fills the parent container.

Blur Placeholder

Show a blurred version of the image while it loads:

Static Import (Recommended)

import heroImage from "@/public/images/hero.jpg";

<Image
  src={heroImage}
  alt="Hero image"
  placeholder="blur" // Automatic blur data from static import
  priority
/>

Static imports automatically generate blur data at build time. This is the easiest approach.

Dynamic Images

For dynamic images, provide blurDataURL:

<Image
  src={imageUrl}
  alt="Dynamic image"
  width={800}
  height={500}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..." // Tiny base64 image
/>

Generate the blur data URL on the server when processing images.

Remote Images

Configure allowed remote image domains in next.config.ts:

// next.config.ts
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "images.unsplash.com",
      },
      {
        protocol: "https",
        hostname: "cdn.yourdomain.com",
      },
    ],
  },
};

export default nextConfig;

Common Mistakes

1. Missing width and height

Without dimensions, the browser cannot reserve space, causing layout shift (CLS).

// Bad: No dimensions
<Image src="/photo.jpg" alt="Photo" />

// Good: Dimensions provided
<Image src="/photo.jpg" alt="Photo" width={800} height={600} />

2. Priority on too many images

Only the LCP image should have priority. Adding it to every image negates the benefit.

3. Missing sizes prop

Without sizes, responsive images default to the viewport width, causing unnecessarily large downloads.

4. Using img instead of Image

The native <img> tag gets none of the optimizations. Always use the Next.js Image component.

5. Enormous source images

Even with optimization, starting with a 5000x3000px image wastes processing time. Resize source images to max 2x the display size.

Image Formats

Next.js Image serves modern formats automatically:

FormatBrowser SupportUse Case
AVIFChrome, FirefoxBest compression, preferred
WebPAll modern browsersGood compression, wide support
JPEGUniversalFallback

The component negotiates the best format based on the browser's Accept header.

Quality Setting

Default quality is 75, which is fine for most images. Adjust for specific cases:

// High quality for hero images
<Image src="/hero.jpg" alt="" width={1200} height={600} quality={85} />

// Lower quality for thumbnails
<Image src="/thumb.jpg" alt="" width={200} height={200} quality={60} />

Measuring Performance

After implementing these optimizations, measure with:

  1. Lighthouse: Check LCP, CLS scores
  2. PageSpeed Insights: Real-world performance data
  3. Chrome DevTools Network tab: Verify image sizes and formats
  4. Web Vitals: Monitor in production with @next/third-parties or Vercel Analytics

Need Performance Optimization?

We optimize Next.js applications for Core Web Vitals across all our projects. Contact us if your site needs performance improvements.

Next.jsimagesperformanceCore Web Vitalstutorial

Ready to Start Your Project?

RCB Software builds world-class websites and applications for businesses worldwide.

Get in Touch

Related Articles