next.js: next/image does not work with CDN

Run next info (available from version 12.0.8 and up)

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 10 Pro
Binaries:
  Node: 16.13.0
  npm: 8.1.0
  Yarn: N/A
  pnpm: N/A
Relevant packages:
  next: 12.0.8
  react: 17.0.2
  react-dom: 17.0.2

What version of Next.js are you using?

12.0.8

What version of Node.js are you using?

16.3.0

What browser are you using?

Chrome

What operating system are you using?

Windows, Linux

How are you deploying your application?

Other platform

Describe the Bug

The issue relates to a previous bug, but that case was closed. However, I believe the issue still persists.

We have the CDN URL specified in the assetPrefix:

// next.config.js
module.exports = {
    assetPrefix: 'https://cdn.example.com'
}

Following the guide from the docs:

Files in the public folder; if you want to serve those assets over a CDN, you’ll have to introduce the prefix yourself

In the code we have the following Image tag:

<Image
    src={`${assetPrefix}/images/cat.jpg`}
    alt="Cat"
    width={30}
    height={30}
/>

But the result in the markup is like this:

<img alt="Cat" src="/_next/image?url=https%3A%2F%2Fcdn.example.com%2Fimages%2Fcat.jpg&amp;w=64&amp;q=75" decoding="async" data-nimg="intrinsic" style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%" srcset="/_next/image?url=https%3A%2F%2Fcdn.example.com%2Fimages%2Fcat.jpg&amp;w=32&amp;q=75 1x, /_next/image?url=https%3A%2F%2Fcdn.example.com%2Fimages%2Fcat.jpg&amp;w=64&amp;q=75 2x">

Expected Behavior

The expected behaviour should be that the initiator URL (src="/_next/image?url...) should also have the CDN prefix, like src="https://cdn.example.com/_next/image?url....

All compiled assets are loaded fine from the CDN by the way… so the _next folder is served from the CDN. That proves the assetPrefix setting is working properly, only the Image is failing.

To Reproduce

Use both <Image> and assetPrefix. Load image from the public folder.

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 20
  • Comments: 16 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Hi I’m running into the same issue. @andreisoare I tried your hack. This is my next.config.js

module.exports = {
  assetPrefix: process.env.VERCEL_URL,
  images: {
    domains: [process.env.VERCEL_URL],
    path: `${process.env.VERCEL_URL}/_next/image`,
  },
};

FWIW the reason I’m using VERCEL_URL as the asset prefix is that my production site is living on a subdomain of another site. The site the client sees is isha.sadhguru.org. Then we setup a reverse proxy from isha.sadhguru.org/isha-yoga-center-california to the url of a Vercel website.

To get assets to load properly on the isha.sadhguru.org website, I need the URLs to be absolute paths to the underlying vercel URL, as relative paths would not get properly reverse-proxied back to the vercel URL.

Regardless, as far as the overall issue is concerned, I’m facing the same basic problem: NextJS Image does not work once I put an assetPrefix. And the path hack didn’t seem to fix it.

Are there any other suggested hacks we can use while we wait for the vercel team to fix the underlying issue?

Looking at the Image component code it seems the default image loader uses the path property in next.config.js -> images. I was able to solve the author’s issue with the following config:

images: {
  domains: [
    ...
  ],
  path: 'https://cdn.com/_next/image',
},

(fwiw I’m using Cloudflare CDN, but that shouldn’t matter)

Just override the Nextjs Image component as below and use this component instead of Next Image:

import NextImage from "next/image";

const Image = ({...props }: any) => {
    const imageLoader = ({src, width, quality}: any) => {
        return `${src}?w=${width}&q=${quality || 75}`
    }

    return (
        <NextImage loader={imageLoader}  {...props} />
    )
  }

export default Image;