The before code installs all dependencies and source code in one image, making it large. The after code builds the app in a full Node image, then copies only the built files and production dependencies into a smaller Alpine image, reducing size and attack surface.
### Before: Single-stage build
FROM node:18
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
CMD ["node", "server.js"]
### After: Multi-stage build
# Build stage
FROM node:18 AS build
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
RUN npm run build
# Final stage
FROM node:18-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/package.json ./
RUN npm install --production
CMD ["node", "dist/server.js"]