Docker cookbook · Beginner

Build a production image for a Node.js service

Package a Node.js or TypeScript service with only production dependencies and a non-root user.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Build in one stage (with dev dependencies for TypeScript), then copy the compiled output and production dependencies into a clean runtime stage that runs as the node user.

Solution

FROM node:24-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

FROM node:24-alpine
ENV NODE_ENV=production
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]

Pitfalls

  • npm install instead of npm ci, giving non-reproducible dependency trees.
  • Copying host node_modules into the image (add it to .dockerignore).
  • Starting with npm start, which adds a process that may not forward signals.

Variations

  • With pnpm, enable Corepack and use pnpm install --frozen-lockfile and pnpm deploy --prod.
  • Bundle the app (esbuild) to ship a single file and skip node_modules entirely.

Further reading: Node.js Docker best practices

Reference: https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md

More Docker recipes

Was this page helpful?