Optimizing Images in Next.js 15

Table of contents

Introduction to next/image
Next.js provides an optimized <Image>
component that enhances performance, responsiveness, and loading efficiency. Unlike the standard <img>
tag, next/image
automatically optimizes images, reducing load times and improving performance.
Why Use next/image
?
Next.js provides an optimized <Image>
component that enhances performance, responsiveness, and loading efficiency. Reasons to use it:
Automatic Optimization: Images are automatically resized and served in modern formats (e.g., WebP, AVIF).
Lazy Loading: By default, images are loaded only when they appear in the viewport.
Responsive Images: Automatically adjusts size based on device resolution.
Built-in Caching & CDN Support: Works well with Vercel’s Image Optimization API and custom loaders.
Better SEO & Performance: Reduces Largest Contentful Paint (LCP) and improves Core Web Vitals.
Setting Up Images in Next.js
1. Storing Local Images
Place local images inside the
/public
folder.Example file structure:
/public ├── example.jpg ├── images/ ├── logo.png
2. Using Local vs. External Images
Scenario | Best Practice |
Static assets like logos, icons | Store in /public and import |
CMS or API-fetched images | Use external URLs with next.config.js setup |
Dynamic user-uploaded images | Store in cloud services (e.g., Cloudinary, S3) |
How to Use <Image>
Effectively
To use the <Image>
component, import it from next/image
:
import Image from "next/image";
export default function Example() {
return (
<Image
src="/example.jpg"
alt="Example Image"
width={500}
height={300}
/>
);
}
Key Points:
src
: Path to the image (local or external).alt
: Improves accessibility and SEO.width
&height
: Required for static images.Automatic lazy loading (enabled by default).
Automatic format conversion (e.g., JPEG to WebP for better compression).
When and How to Use Local vs. External Images
1. Local Images (Static Imports)
When to Use:
Best for images that do not change frequently.
Benefits from Next.js’s built-in optimization and caching.
How to Use:
import exampleImage from "@/public/example.jpg";
<Image src={exampleImage} alt="Static Import" width={500} height={300} />
Use
width
andheight
to define static dimensions.No need for a
next.config.js
update.
Using Local Images Without width
and height
( Not recommended approach )
import exampleImage from "@/public/example.jpg";
<Image src={exampleImage} alt="Static Import" />
Next.js automatically detects the dimensions of static imports.
Not recommended if you need explicit control over image size.
2. External Images (From CMS or Remote URLs)
When to Use:
- When fetching images from CMS, APIs, or cloud storage (e.g., Cloudinary, Pexels, AWS S3).
How to Use:
- Update
next.config.js
to allow external domains:
module.exports = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "example.com",
},
],
},
};
- Use
<Image>
with a remote URL:
<Image src="https://example.com/image.jpg" alt="External" width={500} height={300} />
For dynamic images, use
sizes
instead of fixedwidth
andheight
.Use
fill
for fluid layouts when the parent container determines size.
Achieving Responsiveness with <Image>
1. Using fill
for Flexible Layouts
import Image from "next/image";
export default function ResponsiveImage() {
return (
<div style={{ position: "relative", width: "100%", height: "300px" }}>
<Image src="/example.jpg" alt="Responsive" fill style={{ objectFit: "cover" }} />
</div>
);
}
🔹 fill
allows images to stretch within their parent container.
2. Using sizes
for Different Screen Widths
<Image
src="/example.jpg"
alt="Adaptive Image"
width={800}
height={500}
sizes="(max-width: 768px) 100vw, 50vw"
/>
🔹 sizes
tells Next.js how large the image should be at different viewport widths.
3. When You Don't Know the Image Dimensions
If you know the dimensions of the container but not the image:
<div style={{ width: "100%", height: "300px", position: "relative" }}>
<Image src="/example.jpg" alt="Unknown Size" fill style={{ objectFit: "contain" }} />
</div>
🔹 Ensures the image fits properly without needing exact dimensions.
Optimizing Images for Performance
1. Prioritizing Important Images
Use the priority
prop for images that need to load ASAP (e.g., hero banners):
<Image src="/banner.jpg" alt="Banner" width={1200} height={600} priority />
🔹 Skips lazy loading and preloads the image.
2. Using quality
to Reduce File Size
<Image src="/image.jpg" alt="Optimized" width={500} height={300} quality={75} />
🔹 Lowers file size while maintaining decent quality (default: 75).
3. Implementing Blur Placeholder for Better UX
<Image
src="/image.jpg" alt="Blurred"
width={500} height={300}
placeholder="blur"
blurDataURL="data:image/png;base64,..."
/>
🔹 Shows a low-quality blurred version while loading.
For external images (like the ones where src
is an external link as you mentioned), the placeholder="blur"
property requires a corresponding blurDataURL
property since Next.js can't automatically generate blur placeholders for remote images.
The blurDataURL
should be:
A base64-encoded image URL (usually very small, low-quality version of your image)
Typically under 10KB in size
In the format
data:image/jpeg;base64,ENCODED_DATA
You have a few options for generating this:
Use a library like
plaiceholder
orblurhash
to generate itUse a simple color placeholder (simple base64 encoded small colored image)
Create a standard placeholder that you use for all your images
4. Disabling Lazy Loading for Above-the-Fold Content
<Image src="/logo.png" alt="Logo" width={200} height={100} loading="eager" />
🔹 Use loading="eager"
to load crucial images immediately.
Understanding Lazy Loading and Viewport-Based Loading
How Lazy Loading Works
By default, Next.js images are lazy-loaded.
Images below the fold are only loaded when they enter the viewport.
Better for performance since fewer initial resources are downloaded.
Observing Image Loading Behavior
When resizing the viewport, different image versions are served.
You can check lazy loading using Chrome DevTools → Network tab.
Conclusion
Using next/image
in Next.js 15 significantly improves performance, enhances responsiveness, and provides automatic optimizations. By implementing best practices like prioritization, quality adjustments, and correct sizing, you can ensure fast-loading, scalable, and visually appealing applications. 🚀
Subscribe to my newsletter
Read articles from Tarun directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Tarun
Tarun
I have 3 year-experience as software developer skilled in ReactJS, TypeScript, NextJS, Redux.