I suspect this problem won’t impact too many people. However, it caught me out so I figured I’d document it and share the fix.
Heads up: you’re probably missing a
next.config.js file. Or perhaps you have one, but it’s not got the right setting.
OK, I will first share my config:
FROM node:18-alpine AS base # Install dependencies only when needed FROM base AS deps RUN apk add --no-cache libc6-compat WORKDIR /app # Install dependencies based on the preferred package manager COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ RUN \ if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ elif [ -f package-lock.json ]; then npm ci; \ elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \ else echo "Lockfile not found." && exit 1; \ fi # Rebuild the source code only when needed FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . # Next.js collects completely anonymous telemetry data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the build. ENV NEXT_TELEMETRY_DISABLED 1 # If using npm comment out above and use below instead RUN npm run build # Production image, copy all the files and run next FROM base AS runner WORKDIR /app ENV NODE_ENV production # Uncomment the following line in case you want to disable telemetry during runtime. ENV NEXT_TELEMETRY_DISABLED 1 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static USER nextjs CMD ["node", "server.js"]Code language: Dockerfile (dockerfile)
Dockerfile in the root of my project.
For reference, that’s mostly taken from the NextJS with Docker example on GitHub.
I also have their
.dockerignore file in the project root:
*.sql Dockerfile .dockerignore node_modules npm-debug.log README.md .next .gitCode language: CSS (css)
When building a Docker image, Docker looks for files to include in the image based on the instructions in the
However, sometimes there may be files that are present in the directory where the Dockerfile is located that should not be included in the Docker image. These files could be temporary files, log files, or other files that are not necessary for the application to run in a Docker container.
To exclude these files from being included in the Docker image, you can use a
.dockerignore file. The purpose of a
.dockerignore file is to specify files and directories that should be excluded from the Docker build context, which is the set of files that Docker uses to build the image.
By listing files and directories in the
.dockerignore file, you can ensure that they are not included in the Docker build context and therefore not included in the Docker image. This can help reduce the size of the Docker image and improve the efficiency of the Docker build process.
Dockerfile actually looks a lot nicer in the IDE, thanks to the separators:
Keen eyed viewers will spot I have a couple of extra config lines in the screenshot versus the code sample. The reason for that is to make it so you can easily copy / paste the
Dockerfile code without my custom bits.
OK, so running a
docker build here gives me this:
Sending build context to Docker daemon 2.634MB Step 1/25 : FROM node:18-alpine AS base 2b1b2c7e0c10 Step 2/25 : FROM base AS deps 2b1b2c7e0c10 Step 3/25 : RUN apk add --no-cache libc6-compat Using cache d831fbca573a Step 4/25 : WORKDIR /app Using cache b9541cf0d6a7 Step 5/25 : COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ Using cache 3ea2ca7f55a5 Step 6/25 : RUN if [ -f yarn.lock ]; then yarn --frozen-lockfile; elif [ -f package-lock.json ]; then npm ci; elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; else echo "Lockfile not found." && exit 1; fi Using cache fb63901dc487 Step 7/25 : FROM base AS builder 2b1b2c7e0c10 Step 8/25 : WORKDIR /app Using cache cfebc28e6e0e Step 9/25 : COPY --from=deps /app/node_modules ./node_modules Using cache 7ac119fc48d1 Step 10/25 : COPY . . 557bced0a9cb Step 11/25 : COPY ./.env.build ./.env.local 48cf4f79364a Step 12/25 : ENV NEXT_TELEMETRY_DISABLED 1 Running in 2b104ac949f8 Removing intermediate container 2b104ac949f8 83599a076d59 Step 13/25 : RUN npm run build Running in 324bc1f0535a email@example.com build export NODE_OPTIONS=--openssl-legacy-provider; next build info - Loaded env from /app/.env.local info - Loaded env from /app/.env.production info - Linting and checking validity of types... error - ESLint: Failed to load config "next" to extend from. Referenced from: /app/.eslintrc info - Creating an optimized production build... info - Compiled successfully info - Collecting page data... info - Generating static pages (0/39) info - Generating static pages (9/39) info - Generating static pages (19/39) info - Generating static pages (29/39) info - Generating static pages (39/39) info - Finalizing page optimization... Route (pages) Size First Load JS ┌ ● / 9.11 kB 84.5 kB ├ /_app 0 B 73.3 kB ├ ● /[sector] 1.35 kB 76.7 kB ├ └ /cleaning ├ ● /[sector]/[job-role] (ISR: 10 Seconds) (118094 ms) 120 kB 195 kB ├ ├ /cleaning/cleaning-manager (19748 ms) ├ ├ /cleaning/cleaning-operative (15061 ms) ├ ├ /cleaning/cleaning-assistant (10876 ms) ├ ├ /cleaning/domestic (10119 ms) ├ ├ /cleaning/area-cleaning-manager (6038 ms) ├ ├ /cleaning/cleaning-account-manager (5286 ms) ├ ├ /cleaning/cleaning-contract-manager (3859 ms) ├ └ [+28 more paths] (avg 1682 ms) ├ ○ /404 181 B 73.5 kB ├ λ /api/hello 0 B 73.3 kB └ λ /api/role-to-article 0 B 73.3 kB + First Load JS shared by all 78.6 kB ├ chunks/framework-2c79e2a64abdb08b.js 45.2 kB ├ chunks/main-a0dca5a2ff5035f1.js 26.8 kB ├ chunks/pages/_app-e90929023a77ab46.js 549 B ├ chunks/webpack-8fa1640cc84ba8fe.js 750 B └ css/6f9369f01753e953.css 5.21 kB λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps) ○ (Static) automatically rendered as static HTML (uses no initial props) ● (SSG) automatically generated as static HTML + JSON (uses getStaticProps) (ISR) incremental static regeneration (uses revalidate in getStaticProps) npm notice npm notice New minor version of npm available! 9.3.1 -> 9.5.1 npm notice Changelog: <https://github.com/npm/cli/releases/tag/v9.5.1> npm notice Run `npm install -g firstname.lastname@example.org` to update! npm notice Removing intermediate container 324bc1f0535a cfb984673f22 Step 14/25 : FROM base AS runner 2b1b2c7e0c10 Step 15/25 : WORKDIR /app Using cache cfebc28e6e0e Step 16/25 : ENV NODE_ENV production Using cache 4ac8be51b6e8 Step 17/25 : ENV NEXT_TELEMETRY_DISABLED 1 Using cache 535a61efc955 Step 18/25 : RUN addgroup --system --gid 1001 nodejs Using cache 466c15be1160 Step 19/25 : RUN adduser --system --uid 1001 nextjs Using cache 84726b291022 Step 20/25 : COPY --from=builder /app/public ./public Using cache a9952793e68b Step 21/25 : COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY failed: stat app/.next/standalone: file does not exist make: *** [Makefile:2: docker_build] Error 1Code language: Shell Session (shell)
Again, pretty hard to read as plain text. It doesn’t look that much better in the terminal to be fair.
The crucial bit is the last step – the failed step – step 21 of 25:
And that’s not really super helpful, is it?
Because it’s not saying: hey, you dun goofed here and forgot to provide a
next.config.js file, or that you did and the config you gave was wrong.
I couldn’t find anything to tell me to do this in the official NextJS docs for deploying with Docker. It’s almost as if they would much prefer it if you deployed to Vercel… who would have thought it?
Actually, I have used Vercel to deploy NextJS before and it is absolutely brilliant. But I digress.
The fix here is to provide the necessary config in your
In my case I didn’t even have this file in my project. It needs to live in the project root, by the way, next to where you have your
With that, your project should build. Hopefully.
At least, mine did.