- Published on
Images in Next.js: A Practical Guide
- Authors
🖼️ Introduction
Images are a critical part of the modern web, and Next.js ships with a powerful tool for handling them: next/image
. This built-in component offers significant performance improvements over traditional <img>
tags by enabling automatic optimization, responsive loading, and built-in lazy loading.
In this guide, we'll walk through practical usage of next/image
, highlight its strengths, and cover a few quirks you should know.
next/image
⚙️ How to Use Static Imports
The most optimized approach in Next.js is importing images statically from your project:
import Image from 'next/image'
import oceanPic from '../public/static/images/ocean.jpg'
export default function Gallery() {
return <Image src={oceanPic} alt="Ocean View" placeholder="blur" />
}
Benefits:
- Automatic width/height inference
- Generates multiple sizes and uses modern formats like WebP/AVIF
- Enables blur-up placeholder by default
Dynamic or Remote URLs
You can also load images from remote sources, but you must allow the domain in next.config.js
:
<Image src="https://example.com/images/pic.jpg" alt="Remote image" width={600} height={400} />
In next.config.js
:
module.exports = {
images: {
domains: ['example.com'],
},
}
Using in MDX
If you're using MDX (Markdown with JSX), you can embed the Image
component directly:
import Image from 'next/image'
<Image src="/static/images/sunset.jpg" alt="Sunset" width={800} height={400} />
Alternatively, standard Markdown image syntax works, but it will fall back to a raw <img>
tag unless you configure a custom MDX provider to swap it.

next/image
✅ Benefits of - 🔍 Optimized formats: Serves modern formats (WebP/AVIF) automatically
- 📏 Responsive sizing: Delivers size-appropriate images based on device
- 💤 Lazy loading: Loads images only when visible on screen
- 📐 Layout stability: Helps avoid Cumulative Layout Shift by requiring fixed dimensions
- ⚡ Built-in CDN integration: Works seamlessly with Vercel’s Edge Network
⚠️ Limitations
- 🔒 Public Folder Only: All local images must be stored in the
public
directory - 🌐 Remote images need config: You have to explicitly list external domains
- 🔁 Server dependency: The component requires server-side logic (serverless function or custom server)
- 🛠️ Limited flexibility on non-Vercel platforms: If self-hosting, you must either disable image optimization or configure your own loader/CDN
// next.config.js example to disable optimization:
images: {
unoptimized: true,
}
🧪 Experimental + Alternatives
Next.js is evolving. For build-time static generation or bundler-based processing, you might consider tools like:
These offer more control, but at the cost of setup complexity.
📸 Final Thoughts
The next/image
component is a game-changer for modern frontend development. It's not just about image tags — it's about performance, accessibility, and developer experience.
Use it when you can. Understand its boundaries. And if it doesn't suit your deployment setup, you’ve got alternatives.
Happy optimizing!