In Part 8 , I ripped out SQLite and switched to Postgres. The database was real now β but it still only ran on my laptop. Three terminal tabs. One for go run , one for Redis, one for Postgres. If I closed any of them, the whole thing fell over. It was time to Dockerize. The First Dockerfile: 800MB of Regret My first attempt was a single-stage Dockerfile. Copy everything, build, run: FROM golang:1.25-alpine WORKDIR /app COPY . . RUN go build -o server ./cmd/server CMD ["/app/server"] Enter fullscreen mode Exit fullscreen mode It worked. The image was 800MB. That's bigger than most operating systems. I was shipping the entire Go compiler, my source code, and every dependency just to run a 15MB binary. Multi-Stage Builds: The Aha Moment The fix is a pattern called multi-stage builds. Two FROM statements in one Dockerfile: # STAGE 1: Build (heavy β has Go compiler) FROM golang:1.25-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . .β¦