Docker

Lesson 04

Multi-stage builds

Separate build tooling from the final runtime image so production containers contain only what they need to run.

Good Code

Dockerfile
# Build stages keep install and build tools out of the final image.
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM deps AS build
COPY . .
RUN npm run build

# The runtime stage receives only the files needed to run the app.
FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
CMD ["node", "server.js"]

Bad Code

Dockerfile
# One stage ships source, dev dependencies, and build tools to production.
FROM node:22-alpine
WORKDIR /app

COPY . .
RUN npm install
RUN npm run build

CMD ["npm", "start"]

Review Notes

What to review

Good Code

The good version keeps install and build tooling in earlier stages and copies only runtime artifacts into the final image.

Bad Code

The bad version ships source files, dev dependencies, and build tools in the same image that runs production.

Takeaways

  • Multi-stage builds reduce final image size and separate build concerns from runtime concerns.