Next.js Image Optimization Cheatsheet
Import and Basic Usage
import Image from 'next/image';
export default function MyComponent() {
return (
<Image
src="/hero-image.jpg"
alt="Hero image description"
width={800}
height={600}
priority
/>
);
}
External Images
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/images/*',
},
],
},
};
<Image
src="https://example.com/images/photo.jpg"
alt="External image"
width={500}
height={300}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k="
/>
Fill Container
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image
src="/landscape.jpg"
alt="Landscape"
fill
style={{ objectFit: 'cover' }}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</div>
Responsive Sizes
<Image
src="/product.jpg"
alt="Product"
width={500}
height={300}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
style={{ width: '100%', height: 'auto' }}
/>
Multiple Breakpoints
<Image
src="/banner.jpg"
alt="Banner"
width={1200}
height={400}
sizes="
(max-width: 640px) 100vw,
(max-width: 768px) 80vw,
(max-width: 1024px) 60vw,
50vw
"
/>
Modern Formats
const nextConfig = {
images: {
formats: ['image/webp', 'image/avif'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
};
<Image
src="/photo.jpg"
alt="Photo"
width={800}
height={600}
quality={85}
/>
Quality Settings
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
quality={90}
priority
/>
<Image
src="/thumbnail.jpg"
alt="Thumbnail"
width={150}
height={150}
quality={60}
/>
Priority Loading
<Image
src="/hero-banner.jpg"
alt="Hero banner"
width={1200}
height={400}
priority
/>
Lazy Loading
<Image
src="/gallery-1.jpg"
alt="Gallery image"
width={400}
height={300}
loading="lazy"
/>
Eager Loading
<Image
src="/logo.png"
alt="Logo"
width={200}
height={50}
loading="eager"
/>
Blur Placeholder
<Image
src="/photo.jpg"
alt="Photo"
width={500}
height={300}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k="
/>
Color Placeholder
<Image
src="/product.jpg"
alt="Product"
width={300}
height={200}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k="
style={{ backgroundColor: '#f0f0f0' }}
/>
Loading Component
'use client';
import { useState } from 'react';
import Image from 'next/image';
export default function ImageWithLoader({ src, alt, ...props }) {
const [isLoading, setIsLoading] = useState(true);
return (
<div style={{ position: 'relative' }}>
{isLoading && (
<div style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundColor: '#f0f0f0',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
Loading...
</div>
)}
<Image
src={src}
alt={alt}
{...props}
onLoad={() => setIsLoading(false)}
style={{ opacity: isLoading ? 0 : 1, transition: 'opacity 0.3s' }}
/>
</div>
);
}
Cover (Fill container, maintain aspect ratio)
<div style={{ position: 'relative', width: '300px', height: '200px' }}>
<Image
src="/portrait.jpg"
alt="Portrait"
fill
style={{ objectFit: 'cover' }}
/>
</div>
Contain (Fit entire image, maintain aspect ratio)
<div style={{ position: 'relative', width: '300px', height: '200px' }}>
<Image
src="/landscape.jpg"
alt="Landscape"
fill
style={{ objectFit: 'contain' }}
/>
</div>
Custom Positioning
<div style={{ position: 'relative', width: '400px', height: '300px' }}>
<Image
src="/photo.jpg"
alt="Photo"
fill
style={{
objectFit: 'cover',
objectPosition: 'center top'
}}
/>
</div>
Gallery Grid
export default function ImageGallery({ images }) {
return (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '1rem' }}>
{images.map((image, index) => (
<div key={image.id} style={{ position: 'relative', aspectRatio: '4/3' }}>
<Image
src={image.src}
alt={image.alt}
fill
style={{ objectFit: 'cover' }}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
loading={index < 3 ? 'eager' : 'lazy'}
/>
</div>
))}
</div>
);
}
Hero Section
export default function HeroSection() {
return (
<section style={{ position: 'relative', height: '60vh', minHeight: '400px' }}>
<Image
src="/hero-bg.jpg"
alt="Hero background"
fill
priority
style={{ objectFit: 'cover', objectPosition: 'center' }}
/>
<div style={{
position: 'relative',
zIndex: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100%',
color: 'white'
}}>
<h1>Welcome to Our Site</h1>
</div>
</section>
);
}
Product Card
export default function ProductCard({ product }) {
return (
<div style={{ border: '1px solid #eee', borderRadius: '8px', overflow: 'hidden' }}>
<div style={{ position: 'relative', aspectRatio: '1' }}>
<Image
src={product.image}
alt={product.name}
fill
style={{ objectFit: 'cover' }}
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 25vw"
/>
</div>
<div style={{ padding: '1rem' }}>
<h3>{product.name}</h3>
<p>${product.price}</p>
</div>
</div>
);
}
Configuration Optimization
const nextConfig = {
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
formats: ['image/webp', 'image/avif'],
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/images/*',
},
],
minimumCacheTTL: 60,
},
};
Loading Strategy
export default function Page() {
return (
<div>
{/* Hero image - load immediately */}
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority
/>
{/* Content images - lazy load */}
<div>
<h2>Gallery</h2>
{galleryImages.map((image, index) => (
<Image
key={image.id}
src={image.src}
alt={image.alt}
width={300}
height={200}
loading="lazy"
style={{ marginBottom: '1rem' }}
/>
))}
</div>
</div>
);
}
Error Handling
'use client';
import { useState } from 'react';
import Image from 'next/image';
export default function ImageWithFallback({ src, alt, fallbackSrc, ...props }) {
const [imgSrc, setImgSrc] = useState(src);
const [hasError, setHasError] = useState(false);
return (
<Image
{...props}
src={imgSrc}
alt={alt}
onError={() => {
if (!hasError && fallbackSrc) {
setImgSrc(fallbackSrc);
setHasError(true);
}
}}
/>
);
}
<ImageWithFallback
src="/primary-image.jpg"
fallbackSrc="/fallback-image.jpg"
alt="Product"
width={300}
height={200}
/>
Avatar Images
export default function Avatar({ src, alt, size = 40 }) {
return (
<div style={{
position: 'relative',
width: size,
height: size,
borderRadius: '50%',
overflow: 'hidden'
}}>
<Image
src={src || '/default-avatar.jpg'}
alt={alt}
fill
style={{ objectFit: 'cover' }}
/>
</div>
);
}
Background Images
export default function BackgroundImage({ src, children }) {
return (
<div style={{ position: 'relative' }}>
<Image
src={src}
alt=""
fill
style={{
objectFit: 'cover',
objectPosition: 'center',
zIndex: -1
}}
/>
<div style={{ position: 'relative', zIndex: 1 }}>
{children}
</div>
</div>
);
}
Responsive Logo
export default function Logo({ className }) {
return (
<Image
src="/logo.svg"
alt="Company Logo"
width={150}
height={50}
style={{ width: 'auto', height: 'auto' }}
className={className}
priority
/>
);
}