golangci-lint Configuration
golangci-lint runs many Go analyzers behind one config file and one CLI.
Search across all documentation pages
golangci-lint runs many Go analyzers behind one config file and one CLI.
Teams use .golangci.yml to choose linters, set severity, exclude generated trees, and keep local runs aligned with CI.
Quick-reference recipe card - copy-paste ready.
# Install pinned version (match CI)
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.1.6
# Initialize config interactively
golangci-lint config verify
# Run with repo config
golangci-lint run ./...
# Auto-fix what is safe
golangci-lint run --fix ./...When to reach for this:
go vet is clean but review still catches the same staticcheck issues.vendor/.go.work monorepo.Starter .golangci.yml for a single service module:
run:
timeout: 5m
modules-download-mode: readonly
linters:
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unused
- gosec
- revive
- bodyclose
disable-all: true
linters-settings:
govet:
enable-all: true
revive:
rules:
- name: exported
disabled: true
gosec:
excludes:
- G104 # noisy for fmt.Fprintf to http.ResponseWriter
issues:
exclude-dirs:
- vendor
- third_party
exclude-files:
- ".*\\.pb\\.go$"
- ".*_mock\\.go$"
max-issues-per-linter: 0
max-same-issues: 0Makefile:
GOLANGCI_LINT_VERSION ?= v2.1.6
.PHONY: lint
lint:
golangci-lint run ./...CI job:
- uses: actions/setup-go@v5
with:
go-version: '1.26.x'
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v2.1.6
args: ./...What this demonstrates:
disable-all: true then explicit enable keeps the set intentional.exclude-files skips generated protobuf and mocks.staticcheck, govet, ...).| Stage | Linters | Goal |
|---|---|---|
| 1 | govet, errcheck, gosimple, ineffassign, unused | Baseline correctness |
| 2 | staticcheck | Deeper API and dead code |
| 3 | revive, stylecheck | Consistent naming and comments |
| 4 | gosec, bodyclose | Security and HTTP resource leaks |
| 5 | custom plugins | Org-specific APIs |
# Root: shared defaults
run:
relative-path-mode: gomod
issues:
exclude-dirs:
- vendorPer-module services/billing/.golangci.yml:
linters:
enable:
- gosec
linters-settings:
gosec:
severity: mediumRun from workspace root:
golangci-lint run ./services/billing/...
golangci-lint run ./services/... # all modules with go.mod//nolint:gosec // G304: path validated by caller contract; see SEC-123
os.Open(userPath)Prefer narrow //nolint with ticket over broad exclude-rules regular expressions.
# Verify config syntax
golangci-lint config verify
# List enabled linters
golangci-lint linters
# Debug single linter
golangci-lint run --disable-all -E staticcheck ./...run.timeout: 5m and shard per module in CI matrix.internal/legacy. Fix: Time-boxed exclude with refactor ticket.--fix blindly in CI - Auto-fix can change semantics for some linters. Fix: Run --fix locally or in bot PRs, not silent main commits.go directive. Fix: CI go-version matches go.mod.go vet and golangci-lint - Redundant but acceptable; drop standalone go vet if govet enable-all is on.| Alternative | Use When | Don't Use When |
|---|---|---|
go vet + staticcheck CLI | Minimal dependencies | You want one report and shared excludes |
Custom go/analysis multichecker | Full control, few linters | You need 20 community linters day one |
| Review-only policy | Never at scale | - |
Per-package go:generate lint | Legacy incremental | Replacing centralized config |
Repository root for single-module repos.
Monorepos often use root defaults plus per-module files next to go.mod.
Run golangci-lint migrate and read the v2 changelog.
Update CI action version and config schema together.
Yes.
Many bugs appear only in _test.go files (testinggoroutine, errcheck on failures).
Use --new-from-rev=origin/main or path filters in the workflow for speed.
Keep a nightly full-repo job for drift.
Run golangci-lint per module directory or use path patterns ./... from workspace root with relative-path-mode: gomod.
revive and lll (often disabled as noisy) cover this.
Go community prefers readability over hard column limits; use review for egregious lines.
Presets like standard bundle opinionated sets.
Explicit enable lists are clearer for audit and onboarding docs.
It can run gofmt and goimports linters.
Most teams still enforce format separately for speed and clarity.
Use issues.new exclusions temporarily or fix in dedicated sprint.
Avoid permanent exclude-rules without owners.
After staticcheck and gosec exhaust generic rules.
Build on go/analysis when APIs are internal and stable.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 16, 2026