I use the Next.js Image component for image optimization. It works great on dev but it doesn't load images from external URLs in production.
What can I do?
I use the Next.js Image component for image optimization. It works great on dev but it doesn't load images from external URLs in production.
What can I do?
You need to set the configuration in the next.config.js file first.
For Example:
on next.config.js
module.exports = {
images: {
domains: ['images.unsplash.com'],
},
}
on pages/your_page_file.tsx
<Image
alt="The guitarist in the concert."
src="https://images.unsplash.com/photo-1464375117522-1311d6a5b81f?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=2250&q=80"
width={2250}
height={1390}
layout="responsive"
/>
For versions above 12.3.0 this is the accepted approach:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'assets.example.com',
port: '',
pathname: '/account123/**',
},
],
},
}
Refer https://nextjs.org/docs/messages/next-image-unconfigured-host
remotePatterns. See nextjs.org/docs/messages/next-image-unconfigured-host (domains key is still a working solution)If you want to display any images in nextjs app from accross the internet; here is my next config:
const nextConfig = {
reactStrictMode: true,
i18n,
sassOptions: {
includePaths: [path.join(__dirname, 'src/styles')],
prependData: `@import "variables.scss";`,
},
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**',
port: '',
pathname: '**',
},
],
},
}
I am giving an update for this answer because I change my usage. My new code example like this:
const path = require('path');
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
sassOptions: {
includePaths: [path.join(__dirname, 'src/styles')],
prependData: `@import "variables.scss";`,
},
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '**',
},
{
protocol: 'https',
hostname: 'another-example.com',
port: '',
pathname: '**',
},
],
},
}
export default nextConfig;
I change it because of security. If you know the domain you want to fetch images from, it is better to specify them explicitly rather than using wildcard patterns.
This helps to mitigate potential security risks by limiting the sources from which images can be loaded. It also improves performance by reducing unnecessary network requests to unknown domains.
Add and declare your domain in your next config, next.config.js:
module.exports = {
reactStrictMode: true,
images: {
domains: ["yourDomain.com"],
formats: ["image/webp"],
},
};
The configuration file, next.config.js, should be in the root of your project.
And lastly, restart project even in dev mode.
For future references, I was having the same problem after deploying my next.js site to Netlify. Only later, reading my logs, I found
Image domains set in next.config.js are ignored. Please set the env variable NEXT_IMAGE_ALLOWED_DOMAINS to "cdn.sanity.io" instead
So this is probably something to note. In the meanwhile before I saw it, I plugged this next-sanity-image plugin https://www.sanity.io/plugins/next-sanity-image to my page, which also bypassed the problem
next.config.js to the Docker envionment? Spotted this issue with some useful suggestions in that threadI noticed you're having trouble with next/image not loading external images after deployment. I faced a similar issue, and after some tweaking, here's the configuration that worked for me:
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**',
port: '',
pathname: '**',
},
],
},
}
module.exports = nextConfig
Feel free to give this configuration a try, and let me know if it resolves your problem. If you have any other questions or run into further issues, I'm here to help!
I had the same problem, although I had configured remotePatterns in next.config.js correctly.
Finally, I realized that in my Dockerfile the next.config.js was not copied to the final stage when building the image. As a result, no remote source was allowed during execution and accordingly no image was loaded.
I was able to solve the problem by adding the COPY line for the next.config.js file to the final stage:
COPY --from=builder /app/next.config.js ./
Keep in mind that using environment variables can break this.
I was using Next.js with Docker (using the official Next.js Dockerfile) and AWS Elastic Beanstalk wasn't passing environment variables to the Dockerfile during build. I had a similar next.config.js:
const s3Bucket = process.env.S3_BUCKET;
const nextConfig = {
output: 'standalone',
images: s3Bucket ? { remotePatterns: [{ hostname: s3Bucket }] } : undefined,
};
However, with output: 'standalone', the remotePatterns config option is inlined in the resulting server.js file of the docker image. If you open that file, you would see something like this:
const nextConfig = {/* JSON containing `remotePatterns` */}
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
In my case, since the S3_BUCKET variable was not available, the remotePatterns option was not ending up in the final docker image. So I just had to hardcode the domain in my next.config.js.
I tried many ways to fix it, but nothing worked. Then, I created a next.config.js file in my server's root folder and added my development code inside it. After that, it worked.
Here is the code:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
trailingSlash: false,
eslint: {
ignoreDuringBuilds: true,
},
experimental: {
scrollRestoration: true,
},
images: {
remotePatterns: [
{
protocol: "https",
hostname: "yourdomain.com",
},
],
},
};
module.exports = nextConfig;
I tried the remote pattern method because i was using drive links to preview images and using /uc for google drive wasn't a stable solution at all specially for production so instead of adding additional configuration to my next.config.js/mjs I used another function for proxy images which solved my problem.
Here's the function I used ;
export default async function handler(req, res) {
const { id } = req.query;
if (!id) {
return res.status(400).json({ error: "Missing Google Drive file ID" });
}
const imageUrl = `https://drive.google.com/uc?export=view&id=${id}`;
try {
const response = await fetch(imageUrl);
if (!response.ok) {
return res.status(500).json({ error: "Failed to fetch image from Google Drive" });
}
const contentType = response.headers.get("content-type");
res.setHeader("Content-Type", contentType);
const buffer = await response.arrayBuffer();
res.send(Buffer.from(buffer));
} catch (error) {
console.error(error);
res.status(500).json({ error: "Server error" });
}
}
to use it put this function in you next js /src/pages/api/image-proxy.js
and then use it in your components like
'use client';
import Image from "next/image";
export default function Search() {
return(
<>
<div className="m2">search</div>
<Image src="/api/image-proxy?id=1Yi7hyEGrDj59F7dumyrJCJNt0ib89kmc"
width={2250}
height={1390}
layout="responsive"
/>
</>);
}
For those still experiencing this issue, you can load your image from an external link as shown below:
<Image
src={item.ImageUrl}
alt={`Imagefor ${item.title}`}
width={300}
height={450}
className="h-full w-full object-cover"
data-ai-hint="external image"
unoptimized //<----- just add this option
onError={(e) => {
// Fallback to a placeholder if the image fails to load
e.currentTarget.srcset = 'https://placehold.co/500x750/333333/ffffff?text=Error';
}}
/>