Deploying modern web architectures typically requires packaging multiple application types, such as a Next.js frontend and a Python FastAPI API gateway. If you package these services using standard Dockerfiles, your image sizes will exceed 1GB, containing compilers, package managers, and development dependencies. This slows down CI/CD deployments and increases the server's security attack surface. Multi-Stage Docker builds solve this by compiling code in staging environments and copying only runtime files to the production image.
By structuring Docker stages logically, you can reduce production images to under 150MB, speeding up deployments.
1. Multi-Stage Build for Next.js Frontend
We build our Next.js frontend, separating dependency installation, build phases, and runtime configurations:
# Dockerfile.nextjs
FROM node:18-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:18-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Copy only built assets and package config
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
EXPOSE 3000
CMD ["npm", "start"]
2. Multi-Stage Build for FastAPI Python Backend
For Python microservices, we build virtual environments inside a build stage, stripping out compiler utilities before transferring packages to runtime stages, ensuring lightweight production runtimes.