We use cookies to enhance your experience on the site
CodeWorlds

Next.js Image Component - Image Optimization

Welcome @name! Time to build Treasure Gallery - a pirate photo gallery inspired by Instagram. 📸

Before we start building the gallery, you need to learn how Next.js handles images. Spoiler: much better than a plain

<img>
!

The Problem with Plain <img>

The traditional

<img>
tag has several problems:

No automatic optimization - large files slow down the page ❌ No lazy loading - all images load at once ❌ No responsiveness - one size for all devices ❌ Cumulative Layout Shift (CLS) - the page "jumps" when images load

Next.js Image Component - The Solution

Next.js has a built-in

<Image>
component that automatically:

Optimizes images to WebP/AVIF format ✅ Lazy loading - only loads visible images ✅ Responsive - delivers the right size for the device ✅ Prevents CLS - reserves space before loading

Basic usage:

1import Image from 'next/image';
2
3export default function Gallery() {
4  return (
5    <Image
6      src="/treasure-map.jpg"
7      alt="Treasure map"
8      width={800}
9      height={600}
10    />
11  );
12}

Important: You must provide

width
and
height
- Next.js needs them for optimization.

Images from the public/ folder

Files in the

public/
folder are directly accessible via URL.

Structure:

1public/
2├── images/
3│   ├── treasure-1.jpg
4│   ├── treasure-2.jpg
5│   └── pirate-ship.jpg
6└── logo.png

Usage:

1<Image
2  src="/images/treasure-1.jpg"
3  alt="Golden treasure"
4  width={600}
5  height={400}
6/>

The path starts with

/
- this means the
public/
folder.

External Images (from URL)

You can also load images from external sources, but you need to configure them.

1. Add to next.config.js:

1// next.config.js
2module.exports = {
3  images: {
4    remotePatterns: [
5      {
6        protocol: 'https',
7        hostname: 'images.unsplash.com',
8      },
9      {
10        protocol: 'https',
11        hostname: 'i.imgur.com',
12      },
13    ],
14  },
15};

2. Use the full URL:

1<Image
2  src="https://images.unsplash.com/photo-1234567890"
3  alt="Pirate ship"
4  width={800}
5  height={600}
6/>

fill - Images Filling a Container

When you don't know the exact dimensions or want a responsive image, use

fill
.

1<div className="relative w-full h-96">
2  <Image
3    src="/treasure-map.jpg"
4    alt="Map"
5    fill
6    className="object-cover"
7  />
8</div>

Important:

  • The parent must have
    position: relative
  • Use
    object-cover
    or
    object-contain
    to control scaling

object-cover vs object-contain:

1// object-cover - image fills the container, may be cropped
2<Image
3  src="/wide-image.jpg"
4  alt="Wide image"
5  fill
6  className="object-cover"
7/>
8
9// object-contain - entire image visible, may have empty space
10<Image
11  src="/tall-image.jpg"
12  alt="Tall image"
13  fill
14  className="object-contain"
15/>

Priority - Disabling Lazy Loading

For important images (above the fold - visible immediately), use

priority
:

1<Image
2  src="/hero-banner.jpg"
3  alt="Main banner"
4  width={1200}
5  height={600}
6  priority
7/>

This tells Next.js: "Load this image immediately, don't wait".

Placeholder - Blur Effect While Loading

Next.js can show a blurred placeholder while the image loads:

1<Image
2  src="/treasure.jpg"
3  alt="Treasure"
4  width={600}
5  height={400}
6  placeholder="blur"
7  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..." // Base64 tiny image
8/>

Or automatically for local images:

1import treasureImage from '@/public/treasure.jpg';
2
3<Image
4  src={treasureImage}
5  alt="Treasure"
6  placeholder="blur"
7/>

Practical Example - Instagram Gallery

1import Image from 'next/image';
2
3interface GalleryPost {
4  id: number;
5  imageUrl: string;
6  caption: string;
7  author: string;
8  likes: number;
9}
10
11function GalleryGrid({ posts }: { posts: GalleryPost[] }) {
12  return (
13    <div className="grid grid-cols-3 gap-1">
14      {posts.map((post) => (
15        <div key={post.id} className="relative aspect-square group cursor-pointer">
16          <Image
17            src={post.imageUrl}
18            alt={post.caption}
19            fill
20            className="object-cover"
21          />
22
23          {/* Overlay on hover */}
24          <div className="absolute inset-0 bg-black bg-opacity-50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
25            <div className="text-white text-center">
26              <p className="font-bold">❤️ {post.likes}</p>
27              <p className="text-sm">{post.caption}</p>
28            </div>
29          </div>
30        </div>
31      ))}
32    </div>
33  );
34}

Loading States - Skeleton UI

Show a loading placeholder while images load:

1'use client';
2
3import Image from 'next/image';
4import { useState } from 'react';
5
6export default function PhotoCard({ src, alt }: { src: string; alt: string }) {
7  const [isLoading, setIsLoading] = useState(true);
8
9  return (
10    <div className="relative aspect-square">
11      {isLoading && (
12        <div className="absolute inset-0 bg-gray-200 animate-pulse" />
13      )}
14
15      <Image
16        src={src}
17        alt={alt}
18        fill
19        className={`object-cover transition-opacity duration-300 ${
20          isLoading ? 'opacity-0' : 'opacity-100'
21        }`}
22        onLoad={() => setIsLoading(false)}
23      />
24    </div>
25  );
26}

Sizes - Responsive Sizes

Tell Next.js what image sizes you need for different screens:

1<Image
2  src="/treasure.jpg"
3  alt="Treasure"
4  fill
5  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
6  className="object-cover"
7/>

Meaning:

  • Mobile (≤768px): 100% of viewport width
  • Tablet (≤1200px): 50% of viewport width
  • Desktop: 33% of viewport width

Quality - Quality Control

By default Next.js compresses images to quality=75. You can change this:

1<Image
2  src="/high-quality-art.jpg"
3  alt="Artwork"
4  width={1200}
5  height={800}
6  quality={90} // Higher quality (larger file)
7/>

Summary 🎓

Next.js Image - automatic optimization ✅ width/height - required for local images ✅ fill - responsive images in a container ✅ priority - disable lazy loading for important images ✅ placeholder="blur" - blur effect while loading ✅ object-cover - image fills the container ✅ object-contain - entire image visible ✅ remotePatterns - configuration for external sources ✅ sizes - responsive sizes for optimization

In the next exercise we'll build a gallery grid with modals! 📸

See you there! 🚀

Go to CodeWorlds