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.
