
Next.js Image Not Showing? 5 Reasons Your Images Are Broken
Suman Kumar Keshari
Founder of Skilldham and Software Engineer
You add an image to your Next.js project. You save the file. You refresh the browser.
Nothing.
Just a broken image icon staring back at you - or worse, a completely blank space where your image should be.
You double-check the file path. Looks right. You check the component. Looks fine. You even Google the error - and somehow nothing makes sense.
This is one of the most common frustrations developers face when starting with Next.js. The thing is, Next.js handles images differently from plain HTML. It has its own <Image> component with specific rules - and if you break any of those rules, your image simply won't show.
The good news? Every single one of these issues has a straightforward fix. Let's go through all 5 reasons why your Next.js image is not showing - and exactly how to fix each one.

1. You Are Using the Wrong Image Component
This is the first thing to check when your Next.js image not showing - are you actually using Next.js's built-in Image component, or are you using a plain HTML <img> tag?
Next.js has its own optimized <Image> component imported from next/image. It handles lazy loading, automatic resizing, and format optimization - but it also has strict requirements. If you use a plain <img> tag, you lose all that - and sometimes images simply do not load correctly, especially in production.
Wrong:
jsx
// Plain HTML img tag - no optimization, can break in production
<img src="/images/hero.jpg" alt="Hero image" />Correct:
jsx
import Image from "next/image";
<Image
src="/images/hero.jpg"
alt="Hero image"
width={800}
height={450}
/>The next/image component also requires width and height props when using local images. Without these, Next.js does not know the dimensions of your image and will refuse to render it.
One exception - if you use fill prop instead of width/height, the image fills its parent container. But in that case, the parent must have position: relative and a defined height. Without that, the image disappears completely.
jsx
// Using fill - parent must have position relative + height
<div style={{ position: "relative", height: "400px" }}>
<Image
src="/images/hero.jpg"
alt="Hero image"
fill
className="object-cover"
/>
</div>If you are migrating from plain HTML or an older codebase, this is almost always the first issue to fix.
2. External Image Domain Is Not Whitelisted
If your image is hosted on an external URL - Cloudinary, AWS S3, Unsplash, or any other CDN - and it is not showing in Next.js, the reason is almost certainly a missing domain configuration.
Next.js blocks external images by default for security. You have to explicitly tell Next.js which external domains are allowed to serve images through its <Image> component.
Wrong - no config, image blocked:
jsx
<Image
src="https://res.cloudinary.com/myaccount/image/upload/photo.jpg"
alt="Profile photo"
width={400}
height={400}
/>
```
You will see this error in the console:
```
Error: Invalid src prop on `next/image`, hostname "res.cloudinary.com"
is not configured under images in your `next.config.js`Correct - whitelist the domain in next.config.js:
js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "res.cloudinary.com",
},
{
protocol: "https",
hostname: "images.unsplash.com",
},
],
},
};
module.exports = nextConfig;After adding the domain, restart your dev server - Next.js reads this config only on startup. A hot reload is not enough.
If you are using multiple image sources - Cloudinary for uploads, S3 for static assets - add each one separately in remotePatterns. This is a very common reason why Next.js images stop working after deployment, because the production domain was never added to the config.
For more details on configuring images, the Next.js Image documentation covers all available options.
3. Wrong File Path for Local Images
Local images - images stored inside your project - follow specific path rules in Next.js. Getting the path wrong is one of the most common reasons a Next.js image is not showing, especially for developers coming from other frameworks.
Next.js serves static files from the public folder. The path you write in your src prop should be relative to the public folder - not to your component file.
Wrong - using relative path like plain HTML:
jsx
// This does NOT work in Next.js
<Image src="../../public/images/logo.png" alt="Logo" width={120} height={40} />Correct - path starts from public folder root:
jsx
// File is at: public/images/logo.png
<Image src="/images/logo.png" alt="Logo" width={120} height={40} />The leading / is important - it tells Next.js to look from the root of the public folder.
Also check your folder structure. If your image is at public/assets/images/logo.png, your src should be /assets/images/logo.png - not just /images/logo.png.
Another approach - import local images directly:
For images inside your src or component folders (not in public), you can import them directly. Next.js automatically handles width, height, and optimization:
jsx
import profilePic from "../assets/profile.jpg";
<Image
src={profilePic}
alt="Profile picture"
/>When you import an image this way, you do not need to specify width and height - Next.js reads the dimensions automatically.
If you are unsure where your image actually is, open your browser's Network tab and look at the failed image request URL. It will tell you exactly what path Next.js is trying to load - and you can compare it to your actual file location.
4. Missing CSS - Image Has Zero Width or Height
This one is tricky because the image technically loads - Next.js is not throwing any errors - but you still cannot see it. The image is there in the DOM, but it is invisible.
The culprit is usually CSS. If the image container has no width, no height, or overflow: hidden without proper dimensions, the image renders at zero size or gets clipped completely.
This is especially common when using the fill prop:
Wrong - parent has no height:
jsx
// Image will be invisible — parent has no height
<div className="relative">
<Image src="/hero.jpg" alt="Hero" fill />
</div>Correct - parent has explicit height:
jsx
<div className="relative w-full h-[500px]">
<Image
src="/hero.jpg"
alt="Hero"
fill
className="object-cover"
/>
</div>Another common issue - using width and height props on the <Image> component but then overriding them with CSS to width: 100% without setting height: auto. This distorts or hides the image.
jsx
// Add this to your CSS if image appears squished or invisible
img {
height: auto;
}Open Chrome DevTools, inspect the image element, and check its computed width and height. If you see 0px for either dimension - it is a CSS issue, not a Next.js issue.
5. Image Not Showing After Deployment - Environment Difference
Your images work perfectly on localhost. You deploy to Vercel or another platform. Suddenly - images are broken in production.
This is one of the most frustrating Next.js image issues because it works locally and you cannot reproduce the bug on your machine.
There are three common reasons:
Reason A - Environment variable missing in production:
jsx
// If your image URL uses an env variable
<Image src={process.env.NEXT_PUBLIC_IMAGE_URL + "/photo.jpg"} ... />If NEXT_PUBLIC_IMAGE_URL is not set in your Vercel environment variables, the URL becomes undefined/photo.jpg - broken in production.
Fix: Go to Vercel → Settings → Environment Variables → add all your NEXT_PUBLIC_* variables.
Reason B - next.config.js domain not matching production URL:
js
// You whitelisted dev URL but not production CDN
remotePatterns: [
{ hostname: "localhost" }, // ← dev only
// forgot to add production hostname!
]Add your production image hostname to remotePatterns.
Reason C - Images in public folder not committed to Git:
bash
# Check if public/images is in .gitignore by mistake
cat .gitignoreIf your public/images folder is gitignored, images exist locally but never reach your deployment. Remove it from .gitignore and commit the images.

Key Takeaway
When your Next.js image is not showing, work through this checklist:
Use next/image - not a plain <img> tag
External domains must be whitelisted in next.config.js under remotePatterns
Local image paths start with / and are relative to the public folder
If using fill, parent must have position: relative and a defined height
After deployment, check env variables and confirm your production domain is whitelisted
Most Next.js image issues come down to one of these five reasons. Open your browser console, check the error message, and match it to the fix above.
If you found this useful, you might also want to read Why Your API Works in Postman but Fails in the Browser - another common production debugging issue that trips up a lot of developers.
FAQs
Why is my Next.js image not showing even though the path looks correct? The most common reason is a missing domain in next.config.js for external images, or an incorrect path format for local images. Local paths must start with / and be relative to the public folder — not your component file. Check your browser console for the exact error message.
Why does Next.js Image require width and height? Next.js uses width and height to calculate the image's aspect ratio and prevent layout shift (CLS) during loading. Without these values, the browser does not know how much space to reserve for the image. If you need a fluid image, use the fill prop with a relatively-positioned parent container instead.
Why does my Next.js image work locally but not in production? This almost always comes down to one of three things — a missing environment variable in your deployment platform, a production image hostname not added to remotePatterns in next.config.js, or images in your public folder being excluded from your Git repository via .gitignore.
What is the difference between using fill and width/height in Next.js Image? width and height give the image fixed pixel dimensions — good for logos, avatars, and images with known sizes. fill makes the image expand to fill its parent container — good for hero sections and responsive layouts. When using fill, the parent must have position: relative and a defined height, otherwise the image is invisible.
Does Next.js Image work with Cloudinary and other CDNs? Yes, but you must whitelist the CDN hostname in next.config.js under images.remotePatterns. Without this, Next.js will block the image for security reasons and throw a configuration error in your console.