intermediate
Multi-stage builds
Separate build tooling from runtime images so production containers stay smaller, safer, and easier to scan.
Multi-stage builds keep compilers, dev dependencies, test tooling, and source-only files out of the runtime image. A common Node pattern builds in one stage and copies only `dist` plus production `node_modules` into a slim final stage.
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev
FROM node:20-bookworm-slim
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
USER node
CMD ["node", "dist/server.js"]
Match glibc/musl and CPU architecture between build and runtime when copying native modules.
On interviews: image size, vulnerability surface, reproducible artifacts, native module compatibility, and when build and runtime bases must align.
Common pitfalls: copying `node_modules` across incompatible platforms; omitting migrations, static assets, or Prisma engines from the final stage.
The trade-off is smaller safer images versus build complexity and cross-stage copy discipline.
Checklist:
- Separate build and runtime stages.
- Copy only required outputs.
- Verify native dependency compatibility.
- Render or test the final stage artifact in CI.