Next.js The Image Component

Images are often the heaviest part of a web page. A poorly handled image can slow down your entire site and hurt your search rankings. Next.js provides a built-in Image component that automatically optimizes images for you — without any extra configuration.

The Problem with Regular img Tags

A standard HTML <img> tag sends the original image file to every user, regardless of their screen size or device. A phone receives the same giant image meant for a desktop monitor. This wastes data and slows down page loads.

REGULAR <img> TAG:
Original file: 4000×3000 px, 3MB
User on phone: receives 3MB image → displayed at 400px wide
Result: 2.6MB of data wasted, slow load time

NEXT.JS <Image>:
Original file: 4000×3000 px, 3MB
Next.js resizes → sends 400px wide version, 120KB to phone
Result: fast load, correct size for the device

Importing and Using the Image Component

Import Image from next/image and replace your <img> tags with it. The width and height props are required for local images or images with a known size.

import Image from 'next/image';

export default function Hero() {
  return (
    <Image
      src="/images/hero.jpg"
      alt="A hero banner showing our product"
      width={1200}
      height={600}
    />
  );
}

What Next.js Does Automatically

YOUR IMAGE                NEXT.JS HANDLES
──────────────────────────────────────────────────
Large PNG file    →  Converts to WebP or AVIF (smaller format)
Fixed dimensions  →  Resizes for each device screen size
Above the fold    →  Loads immediately (high priority)
Below the fold    →  Loads only when near the viewport (lazy)
No placeholder    →  Reserves space to prevent layout shift

Local Images vs Remote Images

Local Images (from your project)

Place images in the public/ folder and reference them with a path starting from the root. Next.js automatically knows the width and height of local images.

import Image from 'next/image';

<Image
  src="/images/profile.jpg"
  alt="Profile photo"
  width={300}
  height={300}
/>

Remote Images (from a URL)

For images from external URLs, you must declare the allowed domains in next.config.js. This is a security measure — it prevents your app from loading images from unexpected sources.

// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'images.unsplash.com',
      },
    ],
  },
};
// In your component
<Image
  src="https://images.unsplash.com/photo-123.jpg"
  alt="Mountain landscape"
  width={800}
  height={500}
/>

The fill Prop for Flexible Sizing

When you do not know the exact dimensions of an image, use the fill prop. The image fills its parent container. The parent must have a set size and position: relative.

<div style={{ position: 'relative', width: '100%', height: '400px' }}>
  <Image
    src="/images/banner.jpg"
    alt="Banner"
    fill
    style={{ objectFit: 'cover' }}
  />
</div>

Diagram: fill vs fixed dimensions

FIXED DIMENSIONS:
<Image width={800} height={400} />
→ Image renders at exactly 800×400 pixels

FILL MODE:
Parent div: width 100%, height 400px
<Image fill />
→ Image stretches to fill the parent container
→ Use objectFit to control how it fits (cover, contain)

Priority Images

The image that appears first on your page — usually a hero banner or header photo — should load immediately. Add the priority prop to tell Next.js to load it before anything else.

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

Without priority, images load lazily — they only download when near the visible area of the page. For hero images that appear immediately on load, lazy loading causes a blank space that flashes before the image appears.

The alt Attribute

The alt attribute is required on every Image component. It serves two purposes: it describes the image to screen readers for accessibility, and it provides text that appears if the image fails to load. Write a meaningful description of what the image shows.

GOOD:  alt="A red bicycle parked against a brick wall"
BAD:   alt="image"
BAD:   alt="photo1.jpg"
EMPTY: alt=""   ← Only acceptable for purely decorative images

Diagram: How Lazy Loading Works

PAGE SCROLL POSITION
─────────────────────────────
│  Hero Image  ← priority, loads immediately
│  Text content
│  Text content
│
│  ← User scrolls down
│
│  Product Image  ← loads when 500px away from viewport
│  Product Image  ← loads when 500px away from viewport
│
│  Footer Image   ← loads when user scrolls near it
─────────────────────────────
Result: Initial page load is fast because only visible images load

Image Sizes for Responsive Layouts

When an image appears at different widths on different screen sizes, use the sizes prop to tell the browser how wide the image will be at each breakpoint. This helps Next.js serve the most appropriately sized version.

<Image
  src="/images/card.jpg"
  alt="Product card"
  fill
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>

This tells Next.js: on mobile the image takes 100% of the screen width, on medium screens it takes 50%, and on large screens it takes 33%.

Key Takeaway

Replace all <img> tags with Next.js <Image> components. They automatically resize, convert to modern formats, and lazy-load images. Add priority to your above-the-fold images. Whitelist external image domains in next.config.js. Every image needs a descriptive alt attribute.

Leave a Comment