Go GitHub Actions Workflow Template
Last updated
This is a working .github/workflows/ci.yml for a Go module. It reads the Go version from go.mod, caches modules and build output, runs go vet, golangci-lint and the tests with the race detector.
The workflow
name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go vet ./...
- uses: golangci/golangci-lint-action@v8
with:
version: latest
test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- run: go build ./...
- run: go test -race -count=1 -coverprofile=coverage.out ./...
What the non-obvious parts do
go-version-file: go.moduses the version your module declares, so CI follows thegodirective without a second place to update.- Caching is automatic.
setup-gov4 and later caches the module download cache and the build cache, keyed ongo.sum. This is why there is no separateactions/cachestep.cache-dependency-pathis only needed whengo.sumis not at the repository root, for example in a monorepo. - Two jobs. Lint and test run in parallel on separate machines, so you get the faster of the two as feedback and the slower as total time.
golangci-lint-actionmanages its own cache and annotates the diff. Pin a lint version, notlatest, if you need repeatable results. Check the action's README for the current major version before copying.go test -raceenables the race detector. It slows tests and uses more memory, but catches real concurrency bugs. Remove it if you must, but try it first.-count=1disables Go's test result caching. Results are cached per machine only, so on fresh CI runners it makes no difference, but it keeps runs identical to local-count=1runs.
Variants
Version matrix
Add matrix.go: ["1.23", "1.24"] and use go-version: ${{ matrix.go }} instead of go-version-file. Only needed for libraries; applications should test the version they ship. See matrix builds.
Database tests
Add a services: block. The Django template shows a Postgres service with health checks, and the same block works for Go.
Monorepo
Use working-directory: and a paths: filter, and point cache-dependency-path at each module's go.sum.
Build and release
Add a job that runs go build -trimpath -ldflags="-s -w" and upload the binary as an artifact, or use GoReleaser on tags.
macOS or Windows
Add them to a matrix if you ship binaries for those systems.
Run it on faster machines
Go compiles and tests in parallel, so more cores help directly. Change one line on each job:
runs-on: [self-hosted, Linux, compiler-ci]
The job runs on a fresh 8 vCPU machine from compiler.dev, with a fallback to your original runner. compiler.dev's benchmark of a React and Go app with go test -race went from 6m13s to 2m42s; see benchmarks. More in speed up Go on GitHub Actions and on pricing.
FAQ
Do I need actions/cache for Go modules?
Not with setup-go v4 or later. It caches modules and build output by default.
Why is the first run slow and later runs fast?
The first run populates the build cache. Later runs reuse compiled packages.
Should I run the race detector on every push?
If it fits your time budget, yes. If not, run it on main and nightly.
How do I stop lint from failing on old code?
Set only-new-issues: true in the lint action.
Related
- .NET GitHub Actions Workflow TemplateCopy-paste GitHub Actions CI for .NET with NuGet caching, restore, build and test steps, a SQL Server service option, concurrency and permissions.
- Django GitHub Actions Workflow TemplateCopy-paste GitHub Actions CI for Django with a Postgres service container, pip caching, migrations check and tests, plus concurrency and permissions.
- Docker Build GitHub Actions Workflow TemplateCopy-paste GitHub Actions workflow to build Docker images with Buildx, GitHub cache layers and a push to GHCR on main, with minimal permissions.
- Elixir GitHub Actions Workflow TemplateCopy-paste GitHub Actions CI for Elixir and Phoenix with a Postgres service, deps and _build caching via erlef/setup-beam, plus format and tests.