DEV Community

Sourabh Mandal
Sourabh Mandal

Posted on

Dont Forget to Package Go App the right way in Docker

Subscribe to my channel for Engineering videos @bitsofmandal

Packaging applications with Docker is standard practice today β€” but for production-ready Go apps, image size, startup time, and security matter. In this post, we’ll walk through how to containerize a Go application, then progressively optimize the image size from 45MB to just 4MB using tried-and-tested techniques.


πŸš€ Why Containerize Golang Apps?

  • Go produces statically linked binaries β€” ideal for minimal containers.
  • Containerized apps run reliably across different environments.
  • Optimized containers improve deployment speed, resource usage, and security.

πŸ› οΈ What You’ll Learn

  • How to containerize a Golang app with Docker.
  • Multi-stage builds and their benefits.
  • Reducing image size with Go build flags.
  • Using minimal base images (scratch).
  • Compressing binaries with UPX.
  • Real-world deployment tips and optimizations.

πŸ“– Step 1: Basic Dockerfile

Let’s start simple β€” a basic Dockerfile using the official Go image:

FROM golang:1.24.3

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN go build -o server ./cmd/main.go

EXPOSE 8080
CMD ["./server"]
Enter fullscreen mode Exit fullscreen mode

Image size: 🐳 ~45MB
βœ… Works fine for development, but not production-friendly.

πŸ“– Step 2: Multi-Stage Build

Now, let’s reduce size by separating build-time and runtime environments:

FROM golang:1.24.3 AS build

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o server ./cmd/main.go

FROM golang:1.24.3
WORKDIR /app
COPY --from=build /app/server /server
EXPOSE 8080
CMD ["./server"]
Enter fullscreen mode Exit fullscreen mode

Image size: 🐳 ~38MB
βœ… Keeps runtime image clean β€” no build tools.

πŸ“– Step 3: Minimal Base Image (scratch)

Use a minimal base image like scratch for further optimization:

FROM golang:1.24.3 AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o server ./cmd/main.go

FROM scratch
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]
Enter fullscreen mode Exit fullscreen mode

Image size: 🐳 ~17MB
βœ… Only includes your Go binary β€” nothing else.

Note: Requires statically linked binaries (CGO_ENABLED=0).

πŸ“– Step 4: Go Build Flags

Use Go build flags to strip debugging info:

go build -ldflags="-s -w" -o server ./cmd/main.go
Enter fullscreen mode Exit fullscreen mode

Image size: 🐳 ~12MB
βœ… Smaller binaries, faster startup.

πŸ“– Step 5: UPX Compression

Compress your binary with UPX:

upx --ultra-brute --quiet server
Enter fullscreen mode Exit fullscreen mode

Image size: 🐳 ~4MB
βœ… Drastically reduced size, with negligible startup overhead.


πŸ“¦ Final Optimized Dockerfile

FROM golang:1.24.3-alpine AS build

WORKDIR /app

RUN apk add --no-cache upx

COPY go.mod go.sum ./
RUN go mod download && go mod verify
COPY . .

RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -v \
  -o server \
  -ldflags="-s -w" \
  -installsuffix cgo \
  ./cmd/main.go

RUN upx --ultra-brute --quiet server && upx --test server

FROM scratch

COPY --from=build /app/server /server

ENTRYPOINT ["/server"]
Enter fullscreen mode Exit fullscreen mode

Final image size: 🐳 4MB


πŸ“Š Image Size Summary

Optimization Level Image Size
Basic Golang + Alpine 45MB
+ -ldflags="-s -w" 38MB
+ scratch 17MB
+ UPX 4MB

πŸ’‘ Bonus Tips

  • Use layer caching for faster CI/CD builds.
  • Include SSL certificates if using scratch.
  • Gracefully handle signals for safe shutdowns.
  • Define Docker health checks.
  • Integrate security scanning tools.
  • Measure container performance metrics post-deployment.

πŸ“ˆ Real-World Impact

  • Lower cloud storage and registry costs
  • Faster container startup times
  • Better scaling performance
  • Improved security with minimal attack surface

🎯 Recap: 4 Key Optimization Techniques

  1. βœ… Multi-stage builds to separate build and runtime.
  2. βœ… Go build flags (-ldflags="-s -w") for smaller binaries.
  3. βœ… Using scratch for minimal base images.
  4. βœ… UPX for ultra-light binary compression.

πŸ“š Further Reading

Top comments (0)