Linting & Code Quality Best Practices
Balancing strictness, velocity, and incremental adoption.
Search across all documentation pages
Balancing strictness, velocity, and incremental adoption.
These rules distill the linting-quality section: automate the boring checks, grow linter strictness with the codebase, and keep CI authoritative.
make check in CONTRIBUTING and required CI status checksmake fmt for one-command fixes.go vet ./... on every PR. Vet targets likely bugs the compiler misses.go test ./... green. Quality includes behavior; lint cannot replace tests.go.mod. Toolchain drift causes false green or false red builds.make check.go test -race for services with concurrency. Race failures block merge, not nightly email../... after module changes. Triage reachable CVEs with upgrade PRs, not silent ignores.go mod tidy produces no diff. Keeps go.sum honest in review.*.pb.go and mocks from style linters. Still compile and test generated code.-local prefixes and tool versions to CI. Eliminates "passes locally, fails in pipeline" friction.make lint and make test-race targets. One vocabulary for humans and agents.--no-verify to emergencies with follow-up. Document in team agreement.//nolint with ticket ID and narrow scope. Never blanket-disable linters on packages without owners.make fmt and move on.//nolint count down each quarter.gofmt, go vet, and go test ./... in CI.
Add golangci-lint and race when the team has more than a handful of packages.
Start with govet, errcheck, gosimple, ineffassign, unused, staticcheck.
Add revive and gosec after noise baseline is zero.
OSS can stay at format + vet + test for contributor friction.
Run govulncheck and race in maintainer CI before tags.
Shard per module in matrix, cache modules, use --new-from-rev on PRs.
Keep nightly full-repo scan.
When staticcheck cannot express stable org API rules.
Maintain custom analyzers like production code.
Scope lint to packages that build for each target.
Document excluded build tags in .golangci.yml.
Run go fix on upgrade branches; commit separately from feature work.
Vet may fail until modernizers apply.
Hotfixes still need tests and vet.
Document expedited review, not skipped race/vuln on production paths.
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 18, 2026