Deploying Go Gin Apps
High-performance Go HTTP framework, compile to single binary, deploy to scratch/distroless container or VPS.
PlatformsIntermediate
Why
Go compiles to a single static binary with no runtime dependencies, producing tiny containers (scratch/distroless) with instant startup. Gin adds routing and middleware on top of net/http with 10x performance of Node/Python.
Platform-as-a-Service adoption grew 24% in 2024 as teams shift from VM management to git-push deploys. the cloud infrastructure market reached $330B in 2024, growing 22% year-over-year (Synergy Research), and PaaS layers capture the majority of new workloads.
When
Use Go/Gin for high-performance APIs, microservices, and CLI-served web apps. Choose over Node when binary distribution and low memory matter.
How
1. Build — go build -o server -ldflags="-s -w" main.go (stripped binary)
2. Run — ./server, listens on :8080 by default
3. Docker — multi-stage: golang build, scratch/distroless runtime
4. Binary size — -ldflags="-s -w" strips debug info, UPX for more compression
5. Env — os.Getenv, or godotenv for .env in dev
6. Graceful shutdown — signal.NotifyContext for SIGTERM
7. Cross-compile — GOOS=linux GOARCH=amd64 go build
Example
// main.go — Gin with graceful shutdown
package main
import ("github.com/gin-gonic/gin"; "context"; "os"; "os/signal"; "syscall")
func main() {
r := gin.Default()
r.GET("/health", func(c *gin.Context) { c.JSON(200, gin.H{"ok": true}) })
r.GET("/api", func(c *gin.Context) { c.JSON(200, gin.H{"data": "hello"}) })
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
defer stop()
go r.Run(":8080")
<-ctx.Done()
}
# Dockerfile — multi-stage, distroless
FROM golang:1.22-alpine AS build
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o server -ldflags="-s -w" main.go
FROM gcr.io/distroless/static-debian12
COPY --from=build /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]
Common Problems
- ⚠Binary too large — forgot -ldflags=-s -w, includes debug symbols doubling size
- ⚠CGO_ENABLED=1 in container — needs glibc/musl, use CGO_ENABLED=0 for static binary
- ⚠Container has no shell — distroless/scratch, can't exec into for debugging, use :debug variant
Best Practices
- ✓Use distroless or scratch base image — Go static binary needs no OS, smallest possible container
- ✓Strip binary with -ldflags='-s -w' and consider UPX — reduces 20MB binary to 5-8MB
- ✓Set up health checks and graceful shutdown — handle SIGTERM to drain in-flight requests before exit