Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
menu
  1. Home
  2. /Web Development
  3. /Nextjs
  4. /Image Optimization
Your Progress0%
0 of 70 completed

NextJS Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication

Image Optimization and Best Practices

Advanced techniques for maximum image performance

The Next.js Image component automatically optimizes images, but understanding quality settings, modern formats (WebP, AVIF), responsive sizing, and blur placeholders lets you squeeze every bit of performance. These advanced techniques can reduce image sizes by 50-80% while maintaining quality, dramatically improving Core Web Vitals and user experience. Let's master advanced image optimization!

Image Formats and Conversion

Automatic Format Conversion

Next.js automatically converts images to modern formats:

Format Priority (Automatic)

  1. AVIF - Best compression (20-50% smaller than WebP)
  2. WebP - Great compression (25-35% smaller than JPEG)
  3. JPEG/PNG - Fallback for older browsers
TYPESCRIPT
import Image from 'next/image';

export function OptimizedImage() {
  return (
    <Image
      src="/images/photo.jpg"
      alt="Photo"
      width={800}
      height={600}
    />
  );
}

// What happens:
// 1. User with modern browser → Receives AVIF (smallest)
// 2. User with older browser → Receives WebP
// 3. Very old browser → Receives original JPEG
// ✅ Automatic, no configuration needed
// ✅ Best format for each browser
// ✅ Fallback ensures compatibility

Format Comparison

FormatFile SizeQualityBrowser Support
AVIFSmallest (100KB)Excellent90%+ (Modern browsers)
WebPSmall (150KB)Excellent97%+ (Widespread)
JPEGLarge (200KB)Good100% (Universal)
PNGLargest (400KB)Lossless100% (Universal)

Example savings: A 200KB JPEG becomes 150KB WebP (25% smaller) or 100KB AVIF (50% smaller) with no visible quality loss. Next.js handles this automatically!

Configuring Formats

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    formats: ['image/avif', 'image/webp'],
    // Default: AVIF and WebP enabled
    
    // To disable AVIF (faster builds, larger files):
    // formats: ['image/webp'],
  },
};

module.exports = nextConfig;

// ✅ Default includes both AVIF and WebP
// ✅ AVIF encoding is slower but produces smallest files
// ✅ Can disable AVIF for faster builds in development

Quality Settings

Default Quality (75%)

TYPESCRIPT
import Image from 'next/image';

// Default quality: 75%
export function DefaultQuality() {
  return (
    <Image
      src="/images/photo.jpg"
      alt="Photo"
      width={800}
      height={600}
    />
  );
}

// ✅ 75% provides excellent quality
// ✅ Significant file size reduction
// ✅ Imperceptible quality loss
// ✅ Good default for most images

Custom Quality

TYPESCRIPT
import Image from 'next/image';

// High quality for hero images
export function HeroImage() {
  return (
    <Image
      src="/images/hero.jpg"
      alt="Hero"
      width={1920}
      height={1080}
      quality={90}
      priority
    />
  );
}

// Lower quality for thumbnails
export function Thumbnail() {
  return (
    <Image
      src="/images/thumb.jpg"
      alt="Thumbnail"
      width={150}
      height={150}
      quality={60}
    />
  );
}

// Standard quality for products
export function ProductImage() {
  return (
    <Image
      src="/images/product.jpg"
      alt="Product"
      width={600}
      height={600}
      quality={85}
    />
  );
}

// Quality guidelines:
// 90-100: Hero images, artwork (larger files)
// 75-85: Product images, photos (balanced)
// 50-70: Thumbnails, backgrounds (smaller files)

Quality vs File Size

Example: 1920x1080 Photo

  • Quality 100: 800KB (original)
  • Quality 90: 400KB (50% smaller, imperceptible loss)
  • Quality 75: 200KB (75% smaller, minimal loss)
  • Quality 60: 120KB (85% smaller, acceptable loss)
  • Quality 50: 80KB (90% smaller, noticeable loss)

💡 Sweet spot: 75-85 provides 70-80% size reduction with excellent quality

Responsive Images with Sizes

The sizes Prop

The sizes prop tells the browser which image size to load based on viewport width:

TYPESCRIPT
import Image from 'next/image';

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

// What this means:
// - Mobile (≤768px): Load 100vw (full width)
// - Tablet (≤1200px): Load 50vw (half width)
// - Desktop (>1200px): Load 33vw (third width)

// ✅ Browser loads appropriate size
// ✅ Smaller images on mobile
// ✅ Saves bandwidth
// ✅ Faster loading

Common Sizes Patterns

TYPESCRIPT
// Full-width image (hero, banner)
<Image
  src="/hero.jpg"
  alt="Hero"
  fill
  sizes="100vw"
/>

// Half-width on desktop, full on mobile
<Image
  src="/image.jpg"
  alt="Image"
  fill
  sizes="(max-width: 768px) 100vw, 50vw"
/>

// Three columns on desktop, one on mobile
<Image
  src="/image.jpg"
  alt="Image"
  fill
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>

// Fixed width (doesn't change)
<Image
  src="/avatar.jpg"
  alt="Avatar"
  width={100}
  height={100}
  // No sizes needed for fixed dimensions
/>

// ✅ Match sizes to actual display width
// ✅ Smaller downloads on mobile
// ✅ Better performance

Container-Based Sizing

TYPESCRIPT
// Grid layout: 3 columns on desktop, 1 on mobile
export function ProductGrid() {
  return (
    <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
      {products.map(product => (
        <div key={product.id} className="relative aspect-square">
          <Image
            src={product.image}
            alt={product.name}
            fill
            sizes="(max-width: 768px) 100vw, 33vw"
            className="object-cover"
          />
        </div>
      ))}
    </div>
  );
}

// Mobile: 100vw (full width)
// Desktop: 33vw (three columns)
// ✅ Matches actual layout
// ✅ Optimal image sizes

Article Image Sizing

TYPESCRIPT
// Article with max-width container
export function ArticleImage() {
  return (
    <div className="max-w-3xl mx-auto px-4">
      <Image
        src="/article-image.jpg"
        alt="Article illustration"
        width={1200}
        height={675}
        sizes="(max-width: 768px) 100vw, (max-width: 1200px) 768px, 896px"
        className="w-full h-auto rounded-lg"
      />
    </div>
  );
}

// Mobile: 100vw (full width with padding)
// Tablet: 768px (container max-width)
// Desktop: 896px (max-width: 3xl = 48rem = 768px + padding)
// ✅ Never loads larger than displayed
// ✅ Exact size for each breakpoint

Blur Placeholders

Why Blur Placeholders?

Blur placeholders improve perceived performance by showing something while loading:

❌ Without Placeholder

Empty space → sudden image pop-in → feels slow even if fast

✅ With Blur Placeholder

Blurred preview → gradual reveal → feels instant and smooth

Using Blur Placeholders

TYPESCRIPT
import Image from 'next/image';

export function ImageWithBlur() {
  return (
    <Image
      src="/images/photo.jpg"
      alt="Photo"
      width={800}
      height={600}
      placeholder="blur"
      blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBD..."
    />
  );
}

// placeholder options:
// - 'empty' (default): No placeholder
// - 'blur': Show blur while loading

// ✅ Smooth loading experience
// ✅ Better perceived performance
// ✅ No empty space during load

Generating Blur Data URLs

Several ways to generate base64 blur data:

TYPESCRIPT
// Method 1: Using plaiceholder library
import { getPlaiceholder } from 'plaiceholder';

async function getImage() {
  const { base64 } = await getPlaiceholder('/images/photo.jpg');
  
  return (
    <Image
      src="/images/photo.jpg"
      alt="Photo"
      width={800}
      height={600}
      placeholder="blur"
      blurDataURL={base64}
    />
  );
}

// Method 2: For imported images (automatic)
import photoImage from '../public/images/photo.jpg';

<Image
  src={photoImage}
  alt="Photo"
  placeholder="blur"
  // blurDataURL generated automatically!
/>

// Method 3: Online tools
// Use tools like:
// - https://blurha.sh
// - https://plaiceholder.co
// Generate tiny base64 blur

// ✅ Automatic for imported images
// ✅ Manual for dynamic images
// ✅ Small base64 string (~2-3KB)

Blur Placeholder Example

app/gallery/page.tsx
import Image from 'next/image';
import { getPlaiceholder } from 'plaiceholder';

interface ImageData {
  src: string;
  alt: string;
  blurDataURL: string;
}

async function getImages(): Promise<ImageData[]> {
  const imagePaths = [
    '/images/gallery-1.jpg',
    '/images/gallery-2.jpg',
    '/images/gallery-3.jpg',
  ];

  const images = await Promise.all(
    imagePaths.map(async (src) => {
      const { base64 } = await getPlaiceholder(src);
      return {
        src,
        alt: `Gallery image`,
        blurDataURL: base64,
      };
    })
  );

  return images;
}

export default async function GalleryPage() {
  const images = await getImages();

  return (
    <div className="grid grid-cols-3 gap-4">
      {images.map((image, i) => (
        <div key={i} className="relative aspect-square">
          <Image
            src={image.src}
            alt={image.alt}
            fill
            placeholder="blur"
            blurDataURL={image.blurDataURL}
            className="object-cover"
          />
        </div>
      ))}
    </div>
  );
}

// ✅ Blur generated at build time
// ✅ Smooth loading for all images
// ✅ Better UX

Advanced Configuration

Image Configuration Options

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    // Allowed remote image domains
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        port: '',
        pathname: '/images/**',
      },
    ],
    
    // Image formats (default: AVIF, WebP)
    formats: ['image/avif', 'image/webp'],
    
    // Device sizes for responsive images
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    
    // Image sizes (for different breakpoints)
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
    
    // Minimum cache time (seconds)
    minimumCacheTTL: 60,
    
    // Disable static image imports
    disableStaticImages: false,
    
    // Dangerously allow SVG (use with caution)
    dangerouslyAllowSVG: false,
    contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
  },
};

module.exports = nextConfig;

// ✅ Control optimization behavior
// ✅ Set caching policies
// ✅ Configure remote domains

Custom Loader

next.config.js
// Use custom CDN for image optimization
const nextConfig = {
  images: {
    loader: 'custom',
    loaderFile: './image-loader.js',
  },
};

module.exports = nextConfig;
image-loader.js
// Custom loader for external CDN
export default function myImageLoader({ src, width, quality }) {
  return `https://cdn.example.com/${src}?w=${width}&q=${quality || 75}`;
}

// Use case: External image CDN (Cloudinary, Imgix, etc.)
// ✅ Leverage existing CDN
// ✅ Custom optimization parameters
// ✅ Full control over URL structure

Performance Optimization Strategies

Strategy 1: Prioritize Critical Images

TYPESCRIPT
// Above-the-fold hero image
<Image
  src="/hero.jpg"
  alt="Hero"
  width={1920}
  height={1080}
  priority
  quality={90}
  sizes="100vw"
/>

// Below-the-fold images
<Image
  src="/product.jpg"
  alt="Product"
  width={600}
  height={600}
  // No priority - lazy loads
  quality={75}
/>

// ✅ priority for first image only
// ✅ Rest lazy load
// ✅ Optimal LCP (Largest Contentful Paint)

Strategy 2: Adjust Quality by Use Case

TYPESCRIPT
// High-quality hero images
<Image src="/hero.jpg" quality={90} />

// Standard product images
<Image src="/product.jpg" quality={80} />

// Thumbnails and cards
<Image src="/thumb.jpg" quality={70} />

// Background images
<Image src="/bg.jpg" quality={60} />

// User avatars
<Image src="/avatar.jpg" quality={75} />

// ✅ Higher quality where it matters
// ✅ Lower quality where size matters
// ✅ Balanced approach

Strategy 3: Use Appropriate Dimensions

TYPESCRIPT
// ❌ BAD: Loading 4K image for 400px display
<Image
  src="/huge-4k-image.jpg"  // 3840x2160
  width={400}
  height={300}
/>

// ✅ GOOD: Appropriate size
<Image
  src="/optimized-image.jpg"  // 800x600
  width={400}
  height={300}
/>

// ✅ BETTER: Let Next.js handle it
<div className="w-[400px] h-[300px] relative">
  <Image
    src="/any-size.jpg"
    fill
    sizes="400px"
  />
</div>

// Next.js generates appropriate sizes automatically
// ✅ Serves 400px-800px image (for retina)
// ✅ Not full 4K resolution
// ✅ Optimal file size

Strategy 4: Leverage Caching

next.config.js
const nextConfig = {
  images: {
    // Cache optimized images for 60 days
    minimumCacheTTL: 5184000,
  },
};

// ✅ Long cache time for images
// ✅ Faster subsequent loads
// ✅ Reduced server processing

Measuring Image Performance

Core Web Vitals

Images significantly impact Core Web Vitals:

LCP (Largest Contentful Paint)

Target: <2.5s

Use priority on hero images

Optimize largest image on page

CLS (Cumulative Layout Shift)

Target: <0.1

Always provide width/height

Use fill with aspect ratio

FID (First Input Delay)

Target: <100ms

Lazy load below-fold images

Reduce initial bundle size

Testing Tools

BASH
# Lighthouse (Chrome DevTools)
# Run in Chrome DevTools → Lighthouse tab
# Check Performance score and image metrics

# WebPageTest
# https://webpagetest.org
# Detailed waterfall showing image loads

# Next.js Image Trace
# Enabled automatically in development
# Shows image optimization details in console

# Chrome DevTools Network Tab
# Filter by Img to see all image requests
# Check file sizes and load times

Image Optimization Structure

Organization for optimized images

publicImportant
next.config.jsImportant

Select a file or folder to see details

Image Optimization Best Practices

1. Use Modern Formats (Automatic)

TYPESCRIPT
// ✅ GOOD: Next.js serves AVIF/WebP automatically
<Image src="/photo.jpg" width={800} height={600} />
// Automatically serves AVIF (smallest) or WebP
// 30-50% smaller than JPEG

// ❌ BAD: Using regular <img> tag
<img src="/photo.jpg" />
// Always serves JPEG - larger files

2. Set Appropriate Quality

TYPESCRIPT
// ✅ GOOD: Quality based on use case
<Image src="/hero.jpg" quality={90} />      // Hero
<Image src="/product.jpg" quality={80} />   // Product
<Image src="/thumb.jpg" quality={70} />     // Thumbnail

// ❌ BAD: Always 100% quality
<Image src="/anything.jpg" quality={100} />
// Unnecessarily large files

3. Use sizes for Responsive Images

TYPESCRIPT
// ✅ GOOD: sizes prop for responsive
<Image
  src="/image.jpg"
  fill
  sizes="(max-width: 768px) 100vw, 50vw"
/>

// ❌ BAD: No sizes with fill
<Image src="/image.jpg" fill />
// Loads full-size image on mobile

4. Add Blur Placeholders

TYPESCRIPT
// ✅ GOOD: Blur placeholder
<Image
  src="/photo.jpg"
  width={800}
  height={600}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,..."
/>

// ❌ OKAY: No placeholder (but less smooth)
<Image src="/photo.jpg" width={800} height={600} />
// Works but less smooth loading

5. Prioritize Above-the-Fold Images

TYPESCRIPT
// ✅ GOOD: priority for hero
<Image src="/hero.jpg" priority />

// ✅ GOOD: lazy load below-fold
<Image src="/below-fold.jpg" />
// No priority - lazy loads

// ❌ BAD: priority on everything
<Image src="/image1.jpg" priority />
<Image src="/image2.jpg" priority />
<Image src="/image3.jpg" priority />
// Defeats purpose of priority

Key Takeaways

  • Modern formats - AVIF and WebP automatic (30-80% smaller)
  • Quality settings - 75% default, adjust by use case
  • sizes prop - tells browser which size to load
  • Blur placeholders - improve perceived performance
  • priority prop - preload above-the-fold images
  • Responsive images - smaller on mobile, larger on desktop
  • Core Web Vitals - optimize LCP, CLS, FID
  • Configuration - customize in next.config.js

What's Next?

You've mastered advanced image optimization! Next, we'll explore Working with Static Assets—how to organize assets in the public folder, import images directly, manage different file types, and build a complete asset management strategy for your Next.js projects.

You'll learn folder organization, importing vs referencing, handling icons and fonts, and best practices for managing all static assets in Next.js.

📊 Measure Your Wins

Use Lighthouse to measure before/after. Optimized images typically improve Performance score by 10-30 points and reduce page load time by 40-60%. These are massive wins for user experience!

Test Your Understanding

Question 1 of 4

What is the default quality setting for Next.js images?

Master advanced image optimization in Next.js! Learn quality settings, formats, responsive images, and blur placeholders.

Previous
Next.js Image Component Basics
Next
Working with Static Assets

Complete Image Mastery

Join 2,000+ developers building fast Next.js apps. Get the final images lesson on static asset management - 100% FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

NextJS Tutorials

0 of 70 completed

Your Progress0%

Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo