Image Optimization in Next.js
next/image, blur placeholders, responsive sizes, and lazy loading
What You’ll Build
After following this guide, you will have a working implementation of image optimization in next.js in your project. Next.js Image component automatically optimizes images: serves WebP/AVIF, resizes for the device, lazy loads below the fold, and shows blur placeholders while loading. This can reduce page weight by 50-80% compared to unoptimized images.
Use Cases & Problems Solved
- Implement interactive UI features that users expect from modern apps
- Follow established patterns that scale and remain maintainable
- Reduce boilerplate and avoid common frontend pitfalls
Prerequisites
- Next.js 13+
Step-by-Step Implementation
Basic optimized image
The following snippet shows how to basic optimized image. Copy this into your project and adjust the values for your environment.
import Image from 'next/image';
// Local image — auto blur placeholder
import heroImage from '../public/hero.jpg';
export function Hero() {
return (
<Image
src={heroImage}
alt="Hero banner"
placeholder="blur"
priority // Preload for above-the-fold images
className="w-full h-[400px] object-cover"
/>
);
}
// Remote image — must configure domain
export function UserAvatar({ src, name }) {
return (
<Image
src={src}
alt={name}
width={48}
height={48}
className="rounded-full"
/>
);
}
Responsive image with sizes
The following snippet shows how to responsive image with sizes. Copy this into your project and adjust the values for your environment.
// Serve different sizes based on viewport
<Image
src="/product.jpg"
alt="Product"
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
className="object-cover"
/>
// next.config.js — whitelist remote image domains
module.exports = {
images: {
remotePatterns: [
{ protocol: 'https', hostname: '**.amazonaws.com' },
{ protocol: 'https', hostname: 'avatars.githubusercontent.com' },
],
},
};
⚠️ Don’t Do This
❌ Using
tags with full-size images
// Serves a 4000x3000 image to a 200px thumbnail!
<img src="/photos/vacation.jpg" width="200" />
// Downloads 5MB when only 20KB is needed
✅ Use next/image — auto-resizes to the displayed size
// Serves a properly sized image (e.g., 400x300 WebP = 20KB)
<Image src="/photos/vacation.jpg" width={200} height={150} alt="Vacation" />
// Automatically serves WebP/AVIF, properly sized
Testing
Verify your implementation with these tests:
// __tests__/image-optimization-in-next-js.test.ts
import { describe, it, expect } from 'vitest';
describe('Image Optimization in Next.js', () => {
it('should initialize without errors', () => {
// Test that the setup completes successfully
expect(() => setup()).not.toThrow();
});
it('should handle the primary use case', async () => {
const result = await execute();
expect(result).toBeDefined();
expect(result.success).toBe(true);
});
it('should handle edge cases', async () => {
// Test with empty/null input
const result = await execute(null);
expect(result.error).toBeDefined();
});
});
Verification
# Open DevTools → Network tab → filter by 'Img'
# Check that images are served as WebP/AVIF (not original format)
# Check image dimensions match display size (not oversized)
# Scroll down — images below fold should lazy load
# Run Lighthouse — Image section should be green Related Specs
Next.js Server Actions Guide
Form mutations, revalidation, optimistic updates, and error handling
Infinite Scroll with Virtualization
TanStack Virtual + Intersection Observer for smooth infinite lists