I am using Next.js 15.3.1 on Node.js 22.16. I have the Next.js project configured as a standalone build. When I build the application using npm run build
, a ./.next/standalone
folder is created, containing server.js
, package.json
, a .next
folder, and a node_modules
folder containing dependencies used by my application. Starting the server with node server.js
works perfectly as expected.
I am trying to create a Docker container for this application, but I'm running into a strange issue where the node_modules
folder doesn't get created on build. This makes it impossible to start this server. The package.json
gets created, so if I add another npm install
with --omit=dev
to the Dockerfile, it works perfectly fine. But I think this is not ideal, as it those dependencies should have already been installed from the build, and that just means they won't be cached and will be reinstalled whenever the source code changes. It also probably makes my Docker image larger than it needs to be.
This is my Dockerfile:
# Install build dependencies
FROM node:22.16-bookworm AS dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Build application
FROM node:22.16-bookworm AS builder
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
# Copy source code and build
COPY --from=dependencies /app/node_modules ./node_modules
COPY package.json eslint.config.mjs tsconfig.json ./
COPY . ./frontend
RUN npm run build frontend
# The runtime environment
FROM node:22.16-slim AS runtime
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
# Copy build results, leveraging output traces to reduce image size
COPY --from=builder /app/frontend/.next/standalone /app
COPY --from=builder /app/frontend/public ./public
COPY --from=builder /app/frontend/.next/static ./.next/static
EXPOSE 3000
ENV HOSTNAME="0.0.0.0"
ENV PORT=3000
# Start application
CMD ["node", "server.js"]
It has three phases, one to install the dependencies, one to actually build the standalone app, and then one to take the built app and actually start it. The node_modules
should be in the standalone folder, but they aren't. So I have to add that RUN npm install --omit=dev
line after the COPY
commands.
When I run docker build
, the image is created successfully. It's only when I launch a container that it crashes, because it can't find the module next
--- there is no node_modules
folder.
The issue was how I was copying my file structure in this part:
# Copy source code and build
COPY --from=dependencies /app/node_modules ./node_modules
COPY package.json eslint.config.mjs tsconfig.json ./
COPY . ./frontend
RUN npm run build frontend
I was changing the application structure to try and help with caching, but this wasn't actually necessary and was just causing too many problems. Updating it to this:
# Copy source code and build
COPY --from=dependencies /app/node_modules ./node_modules
COPY . .
RUN npm run build
and changing the rest of the Dockerfile accordingly resolved the issue.