Skip to main content

Next.js Image Component

Images play a crucial role in web applications, but they can significantly impact performance if not handled properly. Next.js provides a built-in Image component that optimizes images automatically, making your applications faster and providing a better user experience.

Introduction to the Image Component

The Image component in Next.js extends the HTML <img> element with features like:

  • Automatic image optimization
  • Lazy loading (images load as they enter the viewport)
  • Preventing layout shift during image loading
  • Responsive images based on device size
  • Modern image formats like WebP when supported by browsers

Getting Started with the Image Component

Basic Usage

First, import the Image component from next/image:

jsx
import Image from 'next/image';

function MyComponent() {
return (
<Image
src="/images/profile.jpg"
alt="Profile picture"
width={500}
height={300}
priority
/>
);
}

In this example:

  • src: The path to your image (local or remote)
  • alt: Accessibility attribute describing the image
  • width and height: Dimensions of the image
  • priority: Boolean that loads the image immediately (important for above-the-fold images)

Output

When rendered, Next.js will:

  • Generate multiple sizes of your image for different devices
  • Serve the image in modern formats like WebP if the browser supports it
  • Only load the image when it enters the viewport (unless priority is set)
  • Prevent layout shift by reserving the space based on width and height

Local vs Remote Images

Local Images

When using local images stored in your project, Next.js can optimize them at build time:

jsx
import Image from 'next/image';
import profilePic from '../public/images/profile.jpg';

function Profile() {
return (
<Image
src={profilePic}
alt="Profile picture"
// width and height are automatically provided
placeholder="blur" // Optional blur-up while loading
/>
);
}

Remote Images

For external images, you need to:

  1. Specify the width and height
  2. Add the domain to your Next.js configuration
jsx
// In your component
import Image from 'next/image';

function Avatar() {
return (
<Image
src="https://example.com/profile.jpg"
alt="Avatar"
width={64}
height={64}
/>
);
}
js
// In next.config.js
module.exports = {
images: {
domains: ['example.com'],
},
}

Responsive Images

Using fill Property

When you want the image to fill its parent container:

jsx
import Image from 'next/image';

function Banner() {
return (
<div style={{ position: 'relative', height: '300px' }}>
<Image
src="/images/banner.jpg"
alt="Website banner"
fill
style={{ objectFit: 'cover' }}
/>
</div>
);
}

Note: The parent element must have position: relative when using fill.

Using sizes for Responsive Behavior

jsx
import Image from 'next/image';

function ResponsiveImage() {
return (
<Image
src="/images/hero.jpg"
alt="Hero image"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
style={{ objectFit: 'contain' }}
/>
);
}

This tells browsers what size the image will be at different breakpoints, helping them select the right image source.

Advanced Features

Image Placeholders

You can show a blur placeholder while the image loads:

jsx
import Image from 'next/image';
import profilePic from '../public/profile.jpg';

function Profile() {
return (
<Image
src={profilePic}
alt="Profile"
placeholder="blur"
// blurDataURL is automatically generated for local images
/>
);
}

For remote images, you can provide a base64-encoded image as placeholder:

jsx
import Image from 'next/image';

function RemoteImageWithBlur() {
return (
<Image
src="https://example.com/photo.jpg"
alt="Remote photo"
width={700}
height={475}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCAAIAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAhEAACAQMDBQAAAAAAAAAAAAABAgMABAUGIWEREiMxUf/EABUBAQEAAAAAAAAAAAAAAAAAAAMF/8QAGhEAAgIDAAAAAAAAAAAAAAAAAAECEgMRkf/aAAwDAQACEQMRAD8AltJagyeH0AthI5xdrLcNM91BF5pX2HaH9bcfaSXWGaRmknyJckliyjqTzSlT54b6bk+h0R//2Q=="
/>
);
}

Loading Priority

For important images (like hero images), use the priority attribute:

jsx
import Image from 'next/image';

function HeroSection() {
return (
<Image
src="/images/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority
/>
);
}

This tells Next.js to load the image immediately, without waiting for it to enter the viewport.

Let's create a responsive image gallery with the Next.js Image component:

jsx
import Image from 'next/image';
import styles from './Gallery.module.css';

const images = [
{ src: '/gallery/image1.jpg', alt: 'Beach sunset', width: 1200, height: 800 },
{ src: '/gallery/image2.jpg', alt: 'Mountain view', width: 800, height: 1200 },
{ src: '/gallery/image3.jpg', alt: 'City skyline', width: 1200, height: 800 },
// More images...
];

function Gallery() {
return (
<div className={styles.gallery}>
{images.map((image, index) => (
<div key={index} className={styles.galleryItem}>
<Image
src={image.src}
alt={image.alt}
width={image.width}
height={image.height}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className={styles.galleryImage}
/>
</div>
))}
</div>
);
}

export default Gallery;

With CSS like:

css
/* Gallery.module.css */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 16px;
padding: 16px;
}

.galleryItem {
position: relative;
height: 300px;
overflow: hidden;
border-radius: 8px;
}

.galleryImage {
object-fit: cover;
transition: transform 0.3s ease;
}

.galleryImage:hover {
transform: scale(1.05);
}

Best Practices

  1. Always specify alt text for accessibility
  2. Use width and height attributes to prevent layout shifts
  3. Add priority to important above-the-fold images
  4. Use the sizes attribute for responsive images
  5. Use fill with objectFit when images need to fill their container
  6. Add domains to next.config.js when using remote images
  7. Consider using placeholder="blur" for better loading experience

Common Issues and Solutions

Issue: "Error: Invalid src prop"

Make sure you've added the domain to your Next.js config:

js
// next.config.js
module.exports = {
images: {
domains: ['example.com', 'cdn.yoursite.com'],
},
}

Issue: Layout shifts

Ensure you always provide:

  • width and height for standard images
  • Proper container styling with position: relative when using fill
jsx
// Good practice
<Image src="/image.jpg" alt="Description" width={800} height={600} />

// For fill mode
<div style={{ position: 'relative', height: '300px' }}>
<Image src="/banner.jpg" alt="Banner" fill style={{ objectFit: 'cover' }} />
</div>

Summary

The Next.js Image component is a powerful tool that helps you:

  • Automatically optimize images for better performance
  • Prevent layout shifts with proper image loading
  • Serve responsive images appropriate for each device
  • Improve loading experience with lazy loading and placeholders

By using this component instead of the standard HTML <img> tag, you ensure your Next.js application delivers images in the most efficient way possible, improving both performance and user experience.

Additional Resources

Exercises

  1. Create a responsive hero section with an optimized background image
  2. Build an image carousel that uses the Image component with proper loading priorities
  3. Convert an existing project using standard <img> tags to use Next.js Image components
  4. Create a photo gallery with blur-up placeholders for a better loading experience


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)