Fix Next.js Docker: Cannot find module '/app/server.js'
Follow the server entrypoint from the Next.js build into the final image, then check the application and its static files separately.
TL;DR#
Error: Cannot find module '/app/server.js' means the container is trying to start an entrypoint that is absent at that path. For a Next.js standalone deployment, enable output: 'standalone' before building, then copy the contents of .next/standalone into the runner's working directory. Keep CMD ["node", "server.js"] aligned with that destination. Copy the static assets separately if this server will serve them.
The Stack Overflow report contains this exact startup failure:
Error: Cannot find module '/app/server.js'Its Dockerfile sets the working directory to /app and starts server.js, but the line that copies standalone output is commented out. The accepted answer adds standalone generation; another answer identifies the missing copy. Both stages of the artifact's journey matter: a generated file left in the builder is still absent from the runner.
Why it happens#
A Next.js build and a Docker image build succeeding are different checks from the runtime entrypoint existing. Docker's multi-stage build documentation explains that each new base stage begins separately and chosen artifacts are transferred between stages. The final stage does not inherit everything produced in the builder merely because it appears later in the Dockerfile.
Next.js's output configuration supplies the other half: standalone mode generates a minimal server and the traced files it needs. An ordinary production build does not select that deployment layout. Copying package.json and static files alone cannot substitute for the generated entrypoint and its dependencies.
Read the filename in the exception literally. This failure happens while Node is locating the script it was asked to execute. It is different from a route failing after the server has started. It also differs from Next.js reporting a missing production build, where the framework has started and cannot find the build artifact it expects. Switching commands without matching their required files trades one incomplete deployment for another.
Fix#
1. Generate the standalone artifact in the build stage#
Merge the following setting into the application's existing next.config.js. Preserve its other options and any wrapper that exports the final configuration:
module.exports = {
output: 'standalone',
}For an existing next.config.mjs, retain its ES module export style instead:
export default {
output: 'standalone',
}Use the configuration file your application already loads; do not create competing files just to add this option. Then rebuild the application. Setting this option only in a runtime environment cannot retroactively create files that were absent from the build. Verify the output in the builder before investigating port mappings or container networking.
The following recipe assumes a single application at the build-context root, an npm lockfile committed beside package.json, and a build script that runs the framework build. A monorepo needs the path adjustment described below.
2. Transfer the output into the final image#
This npm-only Dockerfile follows the artifact layout in the official Next.js Docker example. It includes a file check immediately after the build so a missing entrypoint fails during image creation:
FROM node:24.13.0-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM node:24.13.0-slim AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN mkdir -p public
RUN npm run build
RUN test -f .next/standalone/server.js
FROM node:24.13.0-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
COPY --from=builder --chown=node:node /app/.next/standalone ./
COPY --from=builder --chown=node:node /app/public ./public
COPY --from=builder --chown=node:node /app/.next/static ./.next/static
USER node
EXPOSE 3000
CMD ["node", "server.js"]The copy's destination is significant. Copying the standalone directory's contents to the working directory places the generated entrypoint where the command expects it. Copying those contents to another subdirectory while leaving the command unchanged recreates the missing-path problem. Keep the rest of the traced output alongside the entrypoint; copying only server.js is not a complete release.
The explicit public-directory creation also lets this example copy an empty asset directory when the application does not have one. It does not generate application assets. The standalone documentation states that public files and the framework's static output are not included automatically; the separate copies above supply them for this server to deliver.
3. Keep local output out of the image input#
Add these entries to .dockerignore so the source copy does not overlay the container's installed dependencies with the laptop's node_modules or bring an old local framework build into the builder:
node_modules
.next
.gitDocker documents how .dockerignore excludes files from the build context. The build inside the image should produce the artifact that the runner receives. A directory that exists on your laptop is not evidence that the corresponding image stage contains the right files.
Build and run the image from the directory containing that Dockerfile:
docker build -t next-standalone .
docker run --rm -p 3000:3000 next-standaloneIf image creation instead fails while compiling a statically imported image and names mozjpeg, that is an earlier and separate failure. The Next.js image-decoder build-error article addresses that specific trace; changing the runtime entrypoint cannot repair a failed application build.
Verify the fix#
Check the final image, not just the builder directory. Override its normal command to confirm that the expected entrypoint exists:
docker run --rm --entrypoint sh next-standalone -c 'pwd; test -f server.js && ls -l server.js'Then start it normally and request an application route. Confirm the response contains the expected page, and inspect a loaded stylesheet or script as well. A process reaching its startup banner is weaker evidence than the application and its assets being served. A page that works but has missing styles points to the asset-copy or asset-host configuration, not to the original missing entrypoint.
For this article, the artifact mechanism was reproduced natively on Windows with Next.js 15.5.23, React 19.2.4 and Node 26.7.0. Docker was unavailable, so the Dockerfile above is checked against the official example rather than presented as a container test. The ordinary build created no standalone directory. Enabling only standalone output generated the server; removing only that entrypoint caused MODULE_NOT_FOUND, and restoring it returned HTTP 200 for the page, a generated script and a public asset. Its tracing root includes the repository that supplies its dependencies, which also exercises the nested-layout caveat below.
If startup now succeeds but server-side fetching fails with ECONNREFUSED for another container, continue with the Next.js and Strapi container-address explanation. That is a network destination problem after the server can run, not a reason to undo the standalone copy.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Monorepos and custom servers need their own entrypoint path#
The single-app Dockerfile assumes the generated server is directly under the standalone directory. When the tracing root encompasses a larger repository, inspect the generated tree instead of assuming that location. The output-file-tracing caveats describe widening the tracing root for files outside the application. Preserve the resulting relative layout and point the runtime command at the actual generated server; place public and static assets relative to that application's runtime directory too.
A hand-written server is another distinct arrangement. The custom-server documentation explains that standalone output does not trace custom-server files and emits its own minimal server. Do not replace an application's custom entrypoint with the generated one while assuming its custom behaviour will survive. First decide which deployment model the application uses, then make the build output, copied files and start command agree. For the reported standalone failure, the decisive check is that the generated entrypoint really reaches the exact path Node starts.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix Next.js missing .next/BUILD_ID at server startup
Separate an absent build from the wrong application root, a mismatched output folder and development artifacts, using the file the production server checks.
Fix: sh: 1: next: not found on Heroku
Three different, unrelated situations produce the exact same Heroku crash — here is how to tell which one is yours before you change anything.
Next.js "Failed to load SWC binary": the real fix
Why next dev or next build refuses to start, what actually happens when npm cannot find the right @next/swc binary, and the one reinstall that puts it back — reproduced on Next.js 16.4.2.


