SyntaxStudy
Sign Up
Docker Multi-Stage Builds for Go Static Binaries
Docker Beginner 1 min read

Multi-Stage Builds for Go Static Binaries

Go is an ideal language for multi-stage Docker builds because it compiles to a single static binary with no runtime dependencies. The builder stage uses the full Go toolchain image (several hundred MB); the final stage can be scratch (literally empty) or gcr.io/distroless/static. The resulting image contains only the binary, making it typically 5 to 20 MB — orders of magnitude smaller than an equivalent Python or Node.js image. The Go build command CGO_ENABLED=0 go build -ldflags='-w -s' produces a fully static binary. The -w -s flags strip debug symbols and the symbol table, further reducing binary size. Setting GOARCH and GOOS enables cross-compilation: building a Linux/AMD64 binary on an Apple Silicon Mac is common in CI pipelines. The same pattern applies to Rust, C/C++, and any language with a compilation step. Even interpreted languages benefit: a Python multi-stage build can use a full python:3.12 image to pip-install packages (compiling C extensions) and then copy the virtual environment into a slim python:3.12-slim final stage, avoiding the need for build tools in production.
Example
# Dockerfile - Go application with scratch final stage

# Builder stage
FROM golang:1.22-alpine AS builder

WORKDIR /src

# Download dependencies first (cached layer)
COPY go.mod go.sum ./
RUN go mod download

# Copy source and build static binary
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
    go build -ldflags="-w -s" -o /bin/server ./cmd/server

# Final stage (scratch = empty filesystem)
FROM scratch AS production

# Copy TLS root certificates (needed for HTTPS outbound calls)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt \
     /etc/ssl/certs/

# Copy the static binary only
COPY --from=builder /bin/server /server

# Non-root UID (scratch has no useradd; use numeric UID)
USER 65532:65532

EXPOSE 8080
ENTRYPOINT ["/server"]

# Builder image: ~340 MB (golang:alpine)
# Production image: ~8 MB (scratch + binary)
# docker build -t mygoapp:latest .