CI/CD for a Gin Web Service with GitHub Actions
Vet, lint, race-test, and build your Gin Go service.
Gin is a popular Go HTTP framework. Its CI is standard Go: vet, lint, test with the race detector, and a build. This recipe runs all of them and builds a container image for deploy.
What the pipeline does
- set up Go with module caching
- run go vet
- lint with golangci-lint
- test with -race and coverage
- build and push a Docker image
The workflow
actions/setup-go enables module and build caching automatically. -race catches data races, which matter for a concurrent HTTP server.
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true
- run: go vet ./...
- uses: golangci/golangci-lint-action@v6
- run: go test -race -coverprofile=cover.out ./...
- run: go build -o server ./...
- uses: actions/upload-artifact@v4
with:
name: server
path: serverCaching and speed
setup-go caches the module cache and build cache keyed on go.sum, so dependency downloads and compiles are fast on warm runs. The race-enabled test run is the slow step; cheaper managed runners such as Latchkey (around 69% cheaper than GitHub-hosted) keep it quick and auto-retry transient module proxy failures.
Deploying
Go compiles to a single static binary, so the container can be FROM gcr.io/distroless/static or scratch. Push the image to a registry and deploy to ECS, Cloud Run, Fly.io, or Kubernetes. Build with CGO_ENABLED=0 for a fully static binary.
Key takeaways
- Use -race to catch data races in a concurrent server.
- setup-go caches modules and build output.
- CGO_ENABLED=0 yields a static binary for a scratch image.