rgoussu@goussu: ~/library/go/toolchain
~/library/go/toolchain cat staticcheck-and-golangci-lint.md

staticcheck & golangci-lint — the lint ecosystem

# Static analysis beyond go vet — staticcheck's check catalogue, golangci-lint as the meta-runner, and keeping lint sets small and intentional.

Conceptsaved 2026-08-09 #go#tooling#static-analysis#linting#ci

Overview

go vet ships only high-confidence checks; the community fills the gap. staticcheck is the reference third-party analyser — near-zero false positives, treated by many teams as mandatory as vet — and golangci-lint is the meta-runner that executes it alongside dozens of other linters from one config, one cached pass, one CI step.

Key points

  • staticcheck categories: SA (bugs: misuse of APIs, impossible conditions, concurrency mistakes), S (simplifications), ST (style), QF (quick fixes). SA is the non-negotiable core; SA1019 flags use of Deprecated: APIs.
  • golangci-lint: runs many linters in one process over a shared AST/SSA load; configured via .golangci.yml (enable/disable, per-path excludes, severity); the standard PR gate in Go CI.
  • Enabled-set discipline: enable a small, named list you can defend — typically staticcheck, govet, errcheck, unused + a handful — rather than "enable-all", which churns on every release and buries signal in style noise.
  • errcheck: finds silently dropped error returns — Go's most consequential lint, since the compiler only rejects unused variables, not unused results.
  • revive: the configurable style linter (successor to golint) — naming, comments on exported identifiers, per-rule severity.
  • gosec: security-pattern scanning (hardcoded credentials, weak crypto, command injection) — noisier, worth scoping to the checks you'll act on.
  • False-positive management: prefer narrow inline suppression (//nolint:errcheck // close on read-only file) with a required reason, over global excludes; review nolint growth in code review.
  • New-code-only adoption: on legacy codebases, gate only newly changed lines (--new-from-rev) instead of demanding a big-bang cleanup.

Examples

# .golangci.yml — small and intentional
linters:
  disable-all: true
  enable: [govet, staticcheck, errcheck, unused, ineffassign, gosec]
linters-settings:
  errcheck: { check-type-assertions: true }

Related

  • The go command & tool catalog — parent catalog of the toolchain.
  • go vet — the first-party baseline these tools extend.
  • gopls — surfaces a staticcheck subset live in the editor, before CI sees it.
  • govulncheck — sibling analyser aimed at known vulnerabilities rather than code quality.
  • Code review — lint automates the mechanical findings so review can argue about design.