Nextjs use any domain for image optimization

Nextjs comes with great out of the box techniques to improve web performance. One such optimization is provided by next/image module, which exposes the Image component.

Image component can optimize the images by reducing size as per image container and by converting to better formats like webp. All the images are cached in .next/cache/images

Although there is a caveat, If you want to use images from third-party domains we have to list those domains in next.config.js. If image domains are unknown then there is no way to use a wildcard to allow this.

Solution: Create an image proxy #

⚠️ Warning: Do not use this technique if third party domains are known, List those in next.config.js

Nextjs provides a way to create APIs, We can use that to create a proxy endpoint which passthrough the actual image URLs.

// pages/api/imageproxy.js
export default async (req, res) => {
  const url = decodeURIComponent(req.query.url);
  const result = await fetch(url);
  const body = await result.body;
  body.pipe(res);
};

Now we can use any third party image using url /api/imageproxy?url=${encodeURIComponent(imageURL)}.

<Image
  key={image}
  src={`/api/imageproxy?url=${encodeURIComponent(imageURL)}`}
  width="400px"
  height="320px"
  objectFit="cover"
  quality={80}
/>
Voila now all the images should be optimized and you should see a better lighthouse score #

Abuse concern #

By using Image component API requests will be made only from the server-side. But because API endpoint is publically accessible so it can be abused. Abuse will result in unnecessary CPU utilization and cache Disk space usage.

To prevent this we can use a secret to secure the API
// pages/api/imageproxy.js
export default async (req, res) => {
  const secret = req.query.secret;
  if (secret !== 'mysecret') {
    res.send('error');
    return;
  }
  const url = decodeURIComponent(req.query.url);
  const result = await fetch(url);
  const body = await result.body;
  body.pipe(res);
};

Provide the secret while using image /api/imageproxy?url=${encodeURIComponent(imageURL)}&secret=mysecret.

As someone mentioned on reddit, endpoint will be part of DOM rendered so this wont help with abuse.

Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated ! For feedback, please ping me on Twitter.

Published