Configuring next.config.js to implement Image tag

Hi All, I have two queries on next.config.js.

I am currently using Nextjs for my frontend and Strapi CMS for my backend.

Currently, my Strapi is deployed on DigitalOcean and I have created a Space to store images instead of using a database. Link as follows: https://next-cms-strapi-spaces.sgp1.digitaloceanspaces.com

My main Strapi backend is deployed on DigitalOcean and link is as follows:
https://nextjs-strapi-cms-45gnt.ondigitalocean.app

My front end is deployed on Vercel. I am still trying to figure things on using Nextjs framework and currently would like to use Image instead of img tag, therefore the next.config.js is as follows:

/** @type {import('next').NextConfig} */
module.exports = {
  // output: 'export',
  images: {
    remotePatterns: [
       {
        protocol: 'https',
        hostname: 'next-cms-strapi-spaces.sgp1.digitaloceanspaces.com',
        port: '',
        pathname: '/aa7f294677adda00fa96235a76426c01.jpg'
       },
    ],
  },
};

Qns 1:
I am currently still working on localhost and somehow when I implement the code above into next.config.js; it throws this error. I don’t seem to have a .next/trace in the folder after running npm run build. Is there a way to fix this error?

Error msg:

Error: EPERM: operation not permitted, open 'C:\Users\Harold\OneDrive\Desktop\Course notes\next-reviews\.next\trace'
Emitted 'error' event on WriteStream instance at:
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -4048,
  code: 'EPERM',
  syscall: 'open',
  path: 'C:\\Users\\Harold\\OneDrive\\Desktop\\Course notes\\next-reviews\\.next\\trace'
}

Qns 2. One of the image url link is as follows: https://next-cms-strapi-spaces.sgp1.digitaloceanspaces.com/aa7f294677adda00fa96235a76426c01.jpg, therefore is there a way to make the pathname dynamic? I tried using //http://next-cms-strapi-spaces.sgp1.digitaloceanspaces.com/** , would like to know whether is this the correct method?

Went to did some research and saw someone posted on Github a discussion regarding using an image loader with a cloud provider.
NextJS documentation: Using a cloud provider to optimize images instead of using the Next.js built-in Image Optimization API

Github discussion: Image Component Not Working With DigitalOcean Space ?

Stackoverflow qns: How to cache digitaloceanspaces images with Next/Image

  1. I tried following nextjs documentation by inserting a loader.js file into my root folder

  2. Run npm run build and it shows an error stating that i need to change my server component into client component

  3. insert ‘use-client’ to change my page.jsx from a server to a client component. Ran npm run build, and everything was fine.

  4. Redeployed onto Vercel and this error shows:

Error: Specified images.loaderFile does not exist at "/vercel/path0/my/image/loader.js".
    at assignDefaults (/vercel/path0/node_modules/next/dist/server/config.js:287:23)
    at loadConfig (/vercel/path0/node_modules/next/dist/server/config.js:600:32)
    at async Span.traceAsyncFn (/vercel/path0/node_modules/next/dist/trace/trace.js:103:20)
    at async /vercel/path0/node_modules/next/dist/build/index.js:151:28
    at async Span.traceAsyncFn (/vercel/path0/node_modules/next/dist/trace/trace.js:103:20)
    at async build (/vercel/path0/node_modules/next/dist/build/index.js:146:29)
Error: Command "npm run build" exited with 1

I guess I would stick to img tag for the time being… hopefully, someone out there would have a better solution for this…

Code as follows:

loader.js

const IMAGE_URL = process.env.IMAGE_URL
export default function myImageLoader({ src, width, quality }) {
    return `${IMAGE_URL}/${src}?w=${width}&q=${quality || 75}`
  }

next.config.js

module.exports = {
  images: {
     loader: 'custom',
     loaderFile: './loader.js',
  },

app/reviews/page.jsx

import Link from "next/link";
import Heading from "@/components/Heading";
import { getAllReviews } from "lib/reviews";
import Image from "next/image";
import myImageLoader from "loader";

export const metadata = {
  title: 'Reviews',  
}


export default async function ReviewsPage() {

  const reviews = await getAllReviews();
  // console.log(`ReviewsPage: ${JSON.stringify(reviews, null, 2)}`)
  return (
    <>
      <Heading>Reviews</Heading>

      <nav>
        <ul className="flex flex-row flex-wrap gap-3">
          {reviews.map((review) => (
            <li key={review.slug} className="bg-white border rounded shadow w-80 hover:shadow-xl cursor-pointer">
              <Link href={`/reviews/${review.slug}`} prefetch={false}>
                
                  <Image
                    src={review.image}
                    alt={review.title}
                    quality={1}
                    loader={myImageLoader}
                    width={640}
                    // width="640"
                    height="360"
                    className="rounded-t"
                  />
                  <h2 className="font-semibold font-orbitron py-1 text-center">{review.title}</h2>
                
              </Link>
            </li>
          ))}
        </ul>
      </nav>
    </>
  );
}

Make sure the dev process isn’t running when you run the build command and restart the app when making changes to the config.

You shouldn’t need a pathname if all the images are served from the root of the host.

Example code
/** @type {import('next').NextConfig} */

module.exports = {
  // output: 'export',
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "**.digitaloceanspaces.com",
      },
    ],
  },
};
import Image from "next/image";
import styles from "./page.module.css";

export default function Home() {
  return (
    <main className={styles.main}>
      <div className={styles.description}>
        <Image
          src="https://next-cms-strapi-spaces.sgp1.digitaloceanspaces.com/aa7f294677adda00fa96235a76426c01.jpg"
          alt="Fall Guys"
          width={962}
          height={541}
          priority
        />
      </div>
    </main>
  );
}

More example code

https://github.com/vercel/next.js/tree/canary/examples/image-component


I don’t think you need a custom loader and I didn’t test it. But the path in the error message looks funny. Like it has changed hyphens or spaces to path slashes.

1 Like

hi @lasjorg , thank you and appreciate reading this long post! I used your next.config.js code and deploy it onto vercel once more, it works perfectly!

I missed out the nextjs image api documentation as follows:

Below is another example of the remotePatterns property in the next.config.js file:

next.config.js

module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**.example.com',
      },
    ],
  },
}
Good to know: The example above will ensure the src property of next/image must start with https://img1.example.com or https://me.avatar.example.com or any number of subdomains. Any other protocol or unmatched hostname will respond with 400 Bad Request.

Wildcard patterns can be used for both pathname and hostname and have the following syntax:

* match a single path segment or subdomain
** match any number of path segments at the end or subdomains at the beginning
The ** syntax does not work in the middle of the pattern.

Link: Nextjs Image API

Once again, thanks for the help!

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.