The most common Next.js Image mistake is not failing to display an image. It is copying old examples that still use layout="responsive", layout="fill", or component props such as objectFit. Modern Next.js Image usage centers on width, height, fill, sizes, preload, placeholders, and trusted remote image sources.
What Image does for you
next/image extends the native img element with image optimization features. It can help:
- Serve appropriately sized images for different devices.
- Reduce layout shift by preserving image dimensions.
- Lazy-load non-critical images.
- Support placeholders for important visual areas.
- Apply a consistent pipeline for local and remote images.
It does not decide which image is your LCP image, what responsive size each layout needs, or which remote sources are safe. Those decisions are still yours.
Fixed-size images
import Image from "next/image"
export default function Avatar() {
return (
<Image
src="/images/avatar.png"
alt="Author avatar"
width={160}
height={160}
/>
)
}
width and height describe the intrinsic image size. They help the browser reserve the right aspect ratio, but CSS can still control the final rendered size.
When to use fill
Use fill when the image must cover or fit a parent container whose size is controlled by layout CSS:
<div className="relative h-64 w-full">
<Image
src="/images/hero.jpg"
alt="Hero image"
fill
sizes="100vw"
style={{ objectFit: "cover" }}
/>
</div>
Two rules matter:
- The parent needs positioning, such as
position: relative. - A
fillimage normally needs a correctsizesvalue.
Why sizes matters
Without sizes, the browser may assume an image is close to full viewport width. In a card grid, that can mean downloading a much larger image than needed.
<Image
fill
src="/images/card-cover.jpg"
alt="Article cover"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
style={{ objectFit: "cover" }}
/>
sizes should describe the rendered width of the image at different breakpoints. It is not decoration; it is part of the responsive image contract.
Outdated patterns to stop copying
Old tutorials may show:
<Image layout="responsive" objectFit="cover" />
Use modern props instead:
- Fixed image:
widthandheight - Container-filling image:
fill - Object behavior: CSS class or
style
<Image
fill
src="/images/banner.jpg"
alt="Banner"
style={{ objectFit: "cover", objectPosition: "center" }}
/>
preload, loading, and placeholders
Only the most important above-the-fold image should be considered for preload:
<Image
src="/images/hero.jpg"
alt="Product hero"
width={1440}
height={720}
preload
/>
Do not preload every card image in a list. That competes with the browser's normal prioritization and can make performance worse.
For visual areas where a blank load state feels poor, use a placeholder:
<Image
src="/images/cover.jpg"
alt="Article cover"
width={1200}
height={630}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>
Remote images and remotePatterns
External image URLs must be allowed in Next.js configuration. Modern projects should use remotePatterns rather than copying old domains examples.
This is a security and operational boundary: you are telling the image optimization pipeline which remote hosts and paths it is allowed to fetch.
If the image requires authentication headers, the default optimizer may not be the right tool. Consider public assets, a controlled proxy, or unoptimized only when you understand the tradeoff.
Real project patterns
Article cover:
<Image
src={coverImage}
alt={title}
width={1200}
height={630}
sizes="(max-width: 768px) 100vw, 720px"
style={{ width: "100%", height: "auto" }}
/>
Card thumbnail:
<div className="relative aspect-[16/9] overflow-hidden rounded-lg">
<Image
src={thumbnail}
alt={title}
fill
sizes="(max-width: 768px) 100vw, 33vw"
style={{ objectFit: "cover" }}
/>
</div>
The first is dimension-led. The second is container-led. Mixing the two mental models is where many bugs start.
Related FreeMac guides
- For App Router organization, read Next.js Routing Guide: App Router Patterns.
- For component boundaries, continue with Next.js Server vs Client Components.
- If the page renders differently between server and browser, see React Hydration Failed: Causes, Debugging, and Fixes.
Continue reading
React Hydration Failed: Causes, Debugging, and Fixes
Debug server and client rendering mismatches caused by dates, random values, browser APIs, invalid HTML, local storage, locale differences, and DOM-changing extensions.
11 min readNext.js Routing Guide: App Router Patterns
Learn the current Next.js App Router model: static routes, dynamic segments, catch-all routes, layouts, route groups, parallel routes, and route handlers.
10 min readNext.js Server vs Client Components: How to Choose
Choose between Server Components and Client Components in the Next.js App Router by looking at data access, state, events, browser APIs, serialization, and bundle size.
Subscribe to FreeMac
Weekly picks: free Mac software reviews, trusted source updates, alternatives, and low-friction guides.