We use cookies to enhance your experience on the site
CodeWorlds

Image Component and Image Optimization in Next.js 15

In Metropolis Quantum, visual communication plays a key role. Futuristic holograms, digital billboards, and immersive displays are ubiquitous in the city's landscape. However, just like in real cities, engineers must ensure the efficiency of display systems so that images load quickly and do not consume too many resources.

In the world of web applications, images are one of the biggest obstacles to achieving optimal page performance. Large, uncompressed photos can significantly slow down page loading and worsen the user experience. Fortunately, Next.js 15 offers a powerful tool for image optimization - the

Image
component.

Why is Image Optimization Important?

Before we dive into the details of the

Image
component, it is worth understanding why image optimization is so important:

  1. Page performance - images often make up over 50% of a web page's weight
  2. Core Web Vitals - metrics like LCP (Largest Contentful Paint) are directly related to image loading time
  3. SEO - faster pages are better positioned in search results
  4. User experience - nobody likes waiting for content to load
  5. Data consumption - for mobile users, large images can quickly use up data limits
  6. Accessibility - properly optimized images are more accessible for people with slower internet connections

Traditional Approach to Images in HTML

In traditional HTML, images are usually added using the

<img>
tag:

1<img src="/images/quantum-city.jpg" alt="Panorama Metropolis Quantum" />

This simple approach, however, has several drawbacks:

  1. No automatic optimization - images are served in their original format and size
  2. No responsiveness - images do not automatically adapt to different screen sizes
  3. No lazy loading - all images are loaded immediately, regardless of their visibility
  4. No prioritization - it is not easy to determine which images are critical for displaying the page

Komponent Image w Next.js 15

The

Image
component from Next.js solves these problems and offers a number of additional benefits:

  1. Automatic optimization - conversion to modern formats (WebP, AVIF)
  2. Size adjustment - serving images in the appropriate size for the device
  3. Lazy loading - images are loaded only when they approach the viewport
  4. Avoiding layout shifts - reserving space for images before they load
  5. Support for multiple sources - easy specification of different images for different resolutions
  6. Core Web Vitals optimization - improvement of metrics such as LCP and CLS

Basic Usage of the Image Component

To start using the

Image
component, you first need to import it from
next/image
:

1import Image from 'next/image';
2
3export default function QuantumCityView() {
4  return (
5    <div className="city-view">
6      <h1>Panorama Metropolis Quantum</h1>
7      <Image
8        src="/images/quantum-city.jpg"
9        alt="Panorama Metropolis Quantum z lotu ptaka"
10        width={1200}
11        height={600}
12      />
13    </div>
14  );
15}

In the above example, the

Image
component requires several attributes:

  • src
    - path to the image
  • alt
    - alternative text for accessibility
  • width
    and
    height
    - width and height of the image in pixels

Static Image Imports

Next.js also allows static importing of images, which provides additional benefits such as automatic dimension detection:

1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5  return (
6    <div className="city-view">
7      <h1>Panorama Metropolis Quantum</h1>
8      <Image
9        src={quantumCityImage}
10        alt="Panorama Metropolis Quantum z lotu ptaka"
11        // width and height are automatically determined from image metadata
12      />
13    </div>
14  );
15}

Responsywne obrazy

The

Image
component can be easily adapted to different screen sizes using CSS styles:

1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5  return (
6    <div className="city-view">
7      <h1>Panorama Metropolis Quantum</h1>
8      <div className="relative w-full h-[50vh]">
9        <Image
10          src={quantumCityImage}
11          alt="Panorama Metropolis Quantum z lotu ptaka"
12          fill
13          style={{ objectFit: 'cover' }}
14        />
15      </div>
16    </div>
17  );
18}

In this example:

  • The
    fill
    attribute causes the image to fill the parent container
  • The
    objectFit: 'cover'
    style ensures the image maintains proportions, cropping it if necessary
  • The parent container must have
    relative
    or
    absolute
    positioning

Image Prioritization

For images that are visible "above the fold" (i.e., in the upper part of the page without scrolling), it is worth using the

priority
attribute:

1<Image
2  src="/images/hero-quantum-city.jpg"
3  alt="Panorama Metropolis Quantum"
4  width={1200}
5  height={600}
6  priority
7/>

The

priority
attribute causes:

  • The image is loaded with higher priority
  • Lazy loading is disabled for this image
  • Next.js preloads the image so it is available as soon as possible

Handling Images from CMS or External Sources

To use images from external sources (e.g., CMS, CDN, API), you need to configure the list of allowed domains in the

next.config.js
file:

1// next.config.js
2module.exports = {
3  images: {
4    domains: ['cdn.quantum-city.com', 'images.cms-provider.com'],
5  },
6}

Alternatively, you can use "remotePatterns" for more precise control:

1// next.config.js
2module.exports = {
3  images: {
4    remotePatterns: [
5      {
6        protocol: 'https',
7        hostname: 'cdn.quantum-city.com',
8        port: '',
9        pathname: '/images/**',
10      },
11      {
12        protocol: 'https',
13        hostname: '**.cms-provider.com',
14        port: '',
15        pathname: '/assets/**',
16      },
17    ],
18  },
19}

Placeholders i efekt rozmazania

Next.js 15 offers several ways to improve the user experience during image loading:

Placeholder z efektem blur

1<Image
2  src="/images/quantum-city.jpg"
3  alt="Panorama Metropolis Quantum"
4  width={1200}
5  height={600}
6  placeholder="blur"
7  blurDataURL="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1200' height='600'%3E%3Crect width='100%25' height='100%25' fill='%23071731'/%3E%3C/svg%3E"
8/>

In this example:

  • placeholder="blur"
    enables a blur effect during image loading
  • blurDataURL
    specifies the background color used during image loading (encoded as a base64 URL)

Automatic Blur Effect for Static Imports

When you use a static image import, Next.js automatically generates a blurred version:

1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5  return (
6    <Image
7      src={quantumCityImage}
8      alt="Panorama Metropolis Quantum"
9      placeholder="blur"
10      // blurDataURL jest generowany automatycznie
11    />
12  );
13}

Image Loading Animations

You can add image loading animations using CSS:

1import Image from 'next/image';
2import styles from './image.module.css';
3
4export default function QuantumCityView() {
5  return (
6    <Image
7      src="/images/quantum-city.jpg"
8      alt="Panorama Metropolis Quantum"
9      width={1200}
10      height={600}
11      className={styles.imageTransition}
12    />
13  );
14}
1/* image.module.css */
2.imageTransition {
3  opacity: 0;
4  transition: opacity 0.5s ease-in-out;
5}
6
7.imageTransition:global(.loaded) {
8  opacity: 1;
9}

Zaawansowane funkcje komponentu Image

Adaptatywne obrazy i art direction

If you want to display different images for different screen sizes, you can use the

srcSet
attribute:

1<div className="relative aspect-video w-full">
2  <picture>
3    <source
4      media="(max-width: 640px)"
5      srcSet="/images/quantum-city-mobile.jpg"
6    />
7    <source
8      media="(max-width: 1024px)"
9      srcSet="/images/quantum-city-tablet.jpg"
10    />
11    <source
12      media="(min-width: 1025px)"
13      srcSet="/images/quantum-city-desktop.jpg"
14    />
15    <Image
16      src="/images/quantum-city-desktop.jpg"
17      alt="Panorama Metropolis Quantum"
18      fill
19      style={{ objectFit: 'cover' }}
20    />
21  </picture>
22</div>

Handling Images in Different Formats

Although Next.js automatically converts images to WebP, you can also use the

<picture>
tag to handle different formats:

1<picture>
2  <source srcSet="/images/quantum-city.avif" type="image/avif" />
3  <source srcSet="/images/quantum-city.webp" type="image/webp" />
4  <Image
5    src="/images/quantum-city.jpg"
6    alt="Panorama Metropolis Quantum"
7    width={1200}
8    height={600}
9  />
10</picture>

Handling Images with Transparency

For images with transparency (PNG, SVG), it is worth considering disabling WebP conversion:

1<Image
2  src="/images/quantum-logo.png"
3  alt="Logo Metropolis Quantum"
4  width={200}
5  height={200}
6  style={{ objectFit: 'contain' }}
7  unoptimized
8/>

The

unoptimized
attribute disables Next.js optimization for the given image, which can be useful for:

  • Images with transparency
  • Already optimized images
  • Animated GIFs

Configuring Image Optimization in Next.js 15

Next.js offers many configuration options for image optimization in the

next.config.js
file:

1// next.config.js
2module.exports = {
3  images: {
4    // Allowed domains for external images
5    domains: ['cdn.quantum-city.com'],
6    
7    // More detailed configuration for external images
8    remotePatterns: [
9      {
10        protocol: 'https',
11        hostname: '**.cms-provider.com',
12        port: '',
13        pathname: '/assets/**',
14      },
15    ],
16    
17    // Supported formats
18    formats: ['image/webp', 'image/avif'],
19    
20    // Konfiguracja cache
21    minimumCacheTTL: 60, // w sekundach
22    
23    // Image size limits
24    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
25    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
26    
27    // Custom image loader (e.g., Cloudinary, imgix)
28    loader: 'default',
29    
30    // Path to image optimization endpoint
31    path: '/_next/image',
32    
33    // Disabling automatic optimization for all images
34    unoptimized: false,
35  },
36}

Using External Provider Loaders

Next.js also supports popular image optimization services:

1// next.config.js
2module.exports = {
3  images: {
4    loader: 'cloudinary',
5    loaderFile: './my/image/loader.js',
6    // Domena Cloudinary
7    domains: ['res.cloudinary.com'],
8  },
9}

You can also create your own loader:

1// my/image/loader.js
2export default function myImageLoader({ src, width, quality }) {
3  return `https://cdn.quantum-city.com/images/${src}?w=${width}&q=${quality || 75}`
4}

And use it in the

Image
component:

1import Image from 'next/image';
2import myLoader from '@/my/image/loader';
3
4export default function QuantumCityView() {
5  return (
6    <Image
7      loader={myLoader}
8      src="quantum-city.jpg"
9      alt="Panorama Metropolis Quantum"
10      width={1200}
11      height={600}
12    />
13  );
14}

Practical Application Examples

1. Image Gallery with Lazy Loading

1// components/quantum-gallery.tsx
2import { useState } from 'react';
3import Image from 'next/image';
4
5const images = [
6  { src: '/images/quantum-city-1.jpg', alt: 'Panorama Metropolis Quantum' },
7  { src: '/images/quantum-city-2.jpg', alt: 'Dzielnica Business Quantum' },
8  { src: '/images/quantum-city-3.jpg', alt: 'Parki Kwantowe' },
9  { src: '/images/quantum-city-4.jpg', alt: 'Architektura Kwantowa' },
10  { src: '/images/quantum-city-5.jpg', alt: 'Transport Kwantowy' },
11  // more images...
12];
13
14export default function QuantumGallery() {
15  const [selectedImage, setSelectedImage] = useState(null);
16
17  return (
18    <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
19      <h2 className="text-3xl font-bold mb-6">Galeria Metropolis Quantum</h2>
20      
21      {/* Display selected image */}
22      {selectedImage && (
23        <div className="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50">
24          <div className="max-w-4xl mx-auto p-4">
25            <div className="relative w-full" style={{ height: '80vh' }}>
26              <Image
27                src={selectedImage.src}
28                alt={selectedImage.alt}
29                fill
30                style={{ objectFit: 'contain' }}
31                priority
32              />
33            </div>
34            <button
35              className="absolute top-4 right-4 text-white text-2xl"
36              onClick={() => setSelectedImage(null)}
37            >
38              &times;
39            </button>
40          </div>
41        </div>
42      )}
43      
44      {/* Image grid */}
45      <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
46        {images.map((image, index) => (
47          <div
48            key={index}
49            className="relative aspect-square overflow-hidden rounded-lg cursor-pointer hover:opacity-90 transition-opacity"
50            onClick={() => setSelectedImage(image)}
51          >
52            <Image
53              src={image.src}
54              alt={image.alt}
55              fill
56              style={{ objectFit: 'cover' }}
57              sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, (max-width: 1024px) 33vw, 25vw"
58              // First image is priority, rest are loaded lazily
59              priority={index === 0}
60            />
61          </div>
62        ))}
63      </div>
64    </div>
65  );
66}

2. Responsive Banner with Different Images for Different Devices

1// components/quantum-hero.tsx
2import Image from 'next/image';
3
4export default function QuantumHero() {
5  return (
6    <div className="relative">
7      {/* Image for mobile devices */}
8      <div className="sm:hidden relative h-[50vh]">
9        <Image
10          src="/images/quantum-hero-mobile.jpg"
11          alt="Metropolis Quantum - City of the Future"
12          fill
13          style={{ objectFit: 'cover' }}
14          priority
15        />
16      </div>
17      
18      {/* Image for tablets */}
19      <div className="hidden sm:block md:hidden relative h-[60vh]">
20        <Image
21          src="/images/quantum-hero-tablet.jpg"
22          alt="Metropolis Quantum - City of the Future"
23          fill
24          style={{ objectFit: 'cover' }}
25          priority
26        />
27      </div>
28      
29      {/* Image for desktops */}
30      <div className="hidden md:block relative h-[70vh]">
31        <Image
32          src="/images/quantum-hero-desktop.jpg"
33          alt="Metropolis Quantum - City of the Future"
34          fill
35          style={{ objectFit: 'cover' }}
36          priority
37        />
38      </div>
39      
40      {/* Overlay content */}
41      <div className="absolute inset-0 flex items-center justify-center">
42        <div className="text-center text-white p-4 backdrop-blur-sm bg-black/30 rounded-lg max-w-2xl">
43          <h1 className="text-4xl sm:text-5xl md:text-6xl font-bold mb-4">
44            Metropolis Quantum
45          </h1>
46          <p className="text-xl sm:text-2xl md:text-3xl">
47            The city of the future awaits you
48          </p>
49        </div>
50      </div>
51    </div>
52  );
53}

3. Product Cards with Images

1// components/quantum-product-card.tsx
2import Image from 'next/image';
3import { useState } from 'react';
4
5interface ProductCardProps {
6  product: {
7    id: string;
8    name: string;
9    image: string;
10    price: number;
11    description: string;
12  };
13}
14
15export default function ProductCard({ product }: ProductCardProps) {
16  const [isLoading, setIsLoading] = useState(true);
17  
18  return (
19    <div className="bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden">
20      <div className="relative h-64 w-full bg-gray-200 dark:bg-gray-700">
21        <Image
22          src={product.image}
23          alt={product.name}
24          fill
25          style={{ objectFit: 'cover' }}
26          sizes="(max-width: 768px) 100vw, 33vw"
27          className={`
28            duration-700 ease-in-out
29            ${isLoading ? 'scale-110 blur-xl grayscale' : 'scale-100 blur-0 grayscale-0'}
30          `}
31          onLoadingComplete={() => setIsLoading(false)}
32        />
33      </div>
34      <div className="p-4">
35        <h3 className="text-xl font-semibold mb-2 dark:text-white">{product.name}</h3>
36        <p className="text-gray-600 dark:text-gray-300 mb-2">{product.description}</p>
37        <div className="flex justify-between items-center">
38          <span className="text-lg font-bold dark:text-white">
39            {new Intl.NumberFormat('pl-PL', { style: 'currency', currency: 'PLN' }).format(product.price)}
40          </span>
41          <button className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md">
42            Dodaj do koszyka
43          </button>
44        </div>
45      </div>
46    </div>
47  );
48}

Dobre praktyki przy pracy z komponentem Image

  1. Always specify dimensions - for images with the
    src
    attribute, always define
    width
    and
    height
    or use
    fill
    with a container of defined dimensions
  2. Use the
    sizes
    attribute
    - helps in delivering appropriate image sizes for different devices
  3. Prioritize "above the fold" images - use
    priority
    for images visible without scrolling
  4. Use appropriate formats - let Next.js automatically convert to WebP/AVIF
  5. Optimize for Core Web Vitals - maintain low LCP and CLS
  6. Use static imports for local images
  7. Do not overuse
    unoptimized
    - use only in justified cases
  8. Use meaningful
    alt
    values
    - for accessibility and SEO
  9. Support different formats - configure AVIF and WebP support in
    next.config.js

Image Format Support in Next.js 15

Next.js supports automatic conversion of images to modern formats. By default, Next.js uses the WebP format, which offers good compression while maintaining quality. However, you can also configure support for the AVIF format, which offers even better compression:

1// next.config.js
2module.exports = {
3  images: {
4    formats: ['image/avif', 'image/webp'],
5  },
6}

Image Format Comparison

| Format | Advantages | Disadvantages | Browser Support | |--------|--------|------|----------------------| | JPEG | Widely supported, good for photography | No transparency, larger size than newer formats | All browsers | | PNG | Supports transparency, lossless | Large file size | All browsers | | WebP | Smaller size than JPEG/PNG, supports transparency | Incomplete support in older browsers | ~95% of browsers | | AVIF | Best compression, good quality | Limited browser support, slower encoding | ~70% of browsers |

Debugging and Troubleshooting

Problem: Images are Blurry or Low Quality

Solution: Dostosuj parametr

quality
:

1<Image
2  src="/images/quantum-city.jpg"
3  alt="Panorama Metropolis Quantum"
4  width={1200}
5  height={600}
6  quality={90} // Default is 75
7/>

Problem: Layout Shift During Image Loading

Solution: Always specify image dimensions or use

fill
with a container of defined dimensions:

1<div className="relative w-full aspect-video">
2  <Image
3    src="/images/quantum-city.jpg"
4    alt="Panorama Metropolis Quantum"
5    fill
6    style={{ objectFit: 'cover' }}
7  />
8</div>

Problem: Images are Not Responsive on Different Devices

Solution: Use the

sizes
attribute:

1<Image
2  src="/images/quantum-city.jpg"
3  alt="Panorama Metropolis Quantum"
4  width={1200}
5  height={600}
6  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
7/>

Problem: SVG Images are Not Displaying Properly

Solution: For SVG files, the best option is often to use

unoptimized
:

1<Image
2  src="/images/logo.svg"
3  alt="Logo Metropolis Quantum"
4  width={200}
5  height={200}
6  unoptimized
7/>

Image Optimization Beyond the Image Component

In addition to the

Image
component, it is also worth using other image optimization techniques:

1. Optimizing Images Before Adding to the Project

Before adding images to the project, it is worth optimizing them using tools such as:

  • ImageOptim
  • Squoosh
  • TinyPNG
  • SVGO (for SVG files)

2. Using CDN for Serving Images

Using a CDN (Content Delivery Network) can significantly speed up image delivery:

1// next.config.js
2module.exports = {
3  images: {
4    loader: 'akamai',
5    path: 'https://cdn.quantum-city.com',
6  },
7}

3. Using "Art Direction" Technique for Different Devices

1<picture>
2  <source media="(max-width: 640px)" srcSet="/images/banner-mobile.jpg" />
3  <source media="(max-width: 1024px)" srcSet="/images/banner-tablet.jpg" />
4  <source media="(min-width: 1025px)" srcSet="/images/banner-desktop.jpg" />
5  <img src="/images/banner-fallback.jpg" alt="Banner" />
6</picture>

4. Using "Responsive Images" Technique with
srcset

1<img
2  src="/images/quantum-city.jpg"
3  srcSet="
4    /images/quantum-city-small.jpg 640w,
5    /images/quantum-city-medium.jpg 1024w,
6    /images/quantum-city-large.jpg 1920w
7  "
8  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
9  alt="Panorama Metropolis Quantum"
10/>

Summary

Image optimization is a crucial aspect of creating efficient web applications. Next.js 15 offers a powerful

Image
component that automatically handles many aspects of optimization:

  1. Automatic optimization - conversion to modern formats (WebP, AVIF)
  2. Size adjustment - serving images in the appropriate size for the device
  3. Lazy loading - images are loaded only when they approach the viewport
  4. Avoiding layout shifts - reserving space for images before they load
  5. Support for multiple sources - easy specification of different images for different resolutions

Thanks to these features, you can create applications that load faster, consume less data, and provide a better user experience. Just as the engineers of Metropolis Quantum optimize hologram display systems and digital billboards, you can optimize images in your Next.js application to provide users with a smooth and efficient experience.

In the next chapter, we will learn about different image loading strategies (lazy, eager, priority), which will allow us to further customize image behavior to suit your application's needs.

Go to CodeWorlds