Go Linting
Core Principle
More important than any "blessed" set of linters: lint consistently across a codebase.
Consistent linting helps catch common issues and establishes a high bar for code quality without being unnecessarily prescriptive.
Resource Routing
scripts/setup-lint.sh- Run when generating a.golangci.yml, validating the first lint pass, or producing JSON metadata.assets/golangci.yml- Use as the v2 golangci-lint baseline for established projects.
Setup Procedure
- Create
.golangci.ymlwithscripts/setup-lint.shor copyassets/golangci.yml - Run
golangci-lint run ./... - If errors appear, fix them category by category (formatting first, then vet, then style)
- Re-run until clean
After generating .golangci.yml, run golangci-lint config verify --config .golangci.yml
to verify the configuration schema before relying on lint results.
Minimum Recommended Linters
These linters catch the most common issues while maintaining a high quality bar:
| Linter | Purpose | |--------|---------| | errcheck | Ensure errors are handled | | goimports | Format code and manage imports | | revive | Common style mistakes (modern replacement for golint) | | govet | Analyze code for common mistakes | | staticcheck | Various static analysis checks |
Note:
reviveis the modern, faster successor to the now-deprecatedgolint.
Lint Runner: golangci-lint
Use golangci-lint as your lint runner. See the example .golangci.yml from uber-go/guide.
Example Configuration
Use assets/golangci.yml as the maintained example. It targets
golangci-lint v2 (verified with 2.10.1 on 2026-06-19), keeps goimports
under formatters, and enables the core linters plus common production
additions.
Running
# Install the version this skill's config is verified against
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1
# Run all linters
golangci-lint run
# Run on specific paths
golangci-lint run ./pkg/...
Additional Recommended Linters
Beyond the minimum set, consider these for production projects:
| Linter | Purpose | When to enable | |--------|---------|----------------| | gosec | Security vulnerability detection | Always for services handling user input | | ineffassign | Detect ineffectual assignments | Always — catches dead code | | misspell | Correct common misspellings in comments/strings | Always | | gocyclo | Cyclomatic complexity threshold | When functions exceed ~15 complexity | | exhaustive | Ensure switch covers all enum values | When using iota enums | | bodyclose | Detect unclosed HTTP response bodies | Always for HTTP client code |
Nolint Directives
When suppressing a lint finding, always explain why:
//nolint:errcheck // fire-and-forget logging; error is not actionable
_ = logger.Sync()
Rules:
- Use
//nolint:lintername— never bare//nolint - Place the comment on the same line as the finding
- Include a justification after
//
CI/CD Integration
Run golangci-lint run ./... in CI after tests. Pin the golangci-lint version
used by CI so local and release behavior do not drift.
Pre-commit Hook
#!/bin/sh
# .git/hooks/pre-commit
golangci-lint run --new-from-rev=HEAD~1
Use --new-from-rev to lint only changed code, keeping the feedback loop fast.
Quick Reference
| Task | Command/Action |
|------|----------------|
| Install golangci-lint | go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1 |
| Run linters | golangci-lint run |
| Run on path | golangci-lint run ./pkg/... |
| Config file | .golangci.yml in project root |
| CI integration | Run golangci-lint run in pipeline |
| Nolint directives | //nolint:name // reason — never bare //nolint |
| CI integration | Use golangci/golangci-lint-action for GitHub Actions |
| Pre-commit | golangci-lint run --new-from-rev=HEAD~1 |
Linter Selection Guidelines
| When you need... | Use | |------------------|-----| | Error handling coverage | errcheck | | Import formatting | goimports | | Style consistency | revive | | Bug detection | govet, staticcheck | | All of the above | golangci-lint with config |
Related Skills
- Style foundations: See go-style-core when resolving style questions that linters enforce (formatting, nesting, naming)
- Code review: See go-code-review when combining linter output with a manual review checklist
- Error handling: See go-error-handling when errcheck flags unhandled errors and you need to decide how to handle them
- Testing: See go-testing when running linters alongside tests in CI pipelines