The Problem
Docker images often contain build tools, compilers, and development dependencies that are not needed at runtime. A Go application built in a standard golang image produces a 1+ GB image, when the binary itself is only 10 MB.
Multi-Stage Build Pattern
# Stage 1: Build
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server
# Stage 2: Production (minimal)
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/server /server
EXPOSE 8080
CMD ["/server"]Result: ~15 MB instead of ~1 GB.
Node.js Example
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]PHP/Laravel Example
FROM composer:2 AS deps
WORKDIR /app
COPY composer.* ./
RUN composer install --no-dev --no-scripts
FROM php:8.2-fpm-alpine
COPY --from=deps /app/vendor /var/www/vendor
COPY . /var/www
RUN chown -R www-data:www-data /var/www/storageTips
- Name stages with
ASfor clarity - Copy only production files to the final stage
- Use
.dockerignoreto exclude unnecessary files from the build context