Mastering Go Lint: How to Use Golangci‑lint and Integrate It into Your CI Workflow
Go lint tools, especially Golangci‑lint, provide static code analysis to catch style and correctness issues; this guide explains what lint is, shows common lint warnings, demonstrates installation, configuration, CI integration with GitLab, and practical tips for rolling it out across a development team.
What is lint?
Lint is a form of static code analysis that scans source code without executing it to detect non‑standard coding patterns and potential bugs. For example, writing if foo != false { ... } is less clear than if foo { ... }. A lint program can flag such cases and suggest corrections.
fmt.Sprintf("%d", "123") // error
fmt.Sprintf("%s", "123") // correct
for i, _ := range []int{1,2,3} {} // error
for i := range []int{1,2,3} {} // correct
a := make([]int, 0, 0) // error
a := make([]int, 0) // correct
for _, v := range vs { // error
vectors = append(vectors, v)
}
vectors = append(vectors, vs...) // correctHow to use lint in Go projects
The linting process is driven by a binary executable (the linter). Running the binary scans the project's source code and reports issues. The Go ecosystem offers many open‑source linters; the most versatile choice is Golangci‑lint , a framework that aggregates dozens of linters and allows fine‑grained configuration.
Integrating lint into a team workflow
All developers share the same repository, so a single set of lint rules must be enforced for consistency.
Add the linter execution to the CI pipeline. Every push triggers linting, and the results appear in the merge request. If lint errors are found, merging to the master branch is blocked, ensuring code quality across the team.
Practical implementation
Background: Our team inherited a codebase with many minor issues that were impractical to fix manually, so we introduced linting to automate detection.
CI tool: We use GitLab as the source‑code platform and GitLab CI for continuous integration.
1. Install Golangci‑lint
GOPATH_FIRST=$(echo $(go env GOPATH) | awk -F':' '{ print $1}')
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b ${GOPATH_FIRST}/bin v1.21.02. Configure Golangci‑lint
Create a .golangci.yml file at the project root to enable or disable specific linters and set custom rules.
linters:
disable-all: true
enable:
- deadcode
- gosimple
- govet
- ineffassign
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
- scopelint
linters-settings:
govet:
check-shadowing: true
check-unreachable: true
check-rangeloops: true
check-copylocks: true3. Run the linter
Execute the following command at the project root: golangci-lint run The command reads .golangci.yml (if present), runs the enabled linters, and prints error locations and suggested fixes. If a message is unclear, searching the keyword online often yields detailed explanations.
4. Gradual rollout
Enable simple linters first (e.g., deadcode, unused) and later add stricter ones (e.g., gosimple) so teammates can adapt gradually.
Before turning on a new linter, manually fix all existing violations for that linter, ensuring that future merge requests only need to address new changes.
5. GitLab CI integration
Add a .gitlab-ci.yml file to the repository so that linting runs automatically on each push.
image: registry.company.cn/ee/go:1.12.9-4
stages:
- qa
lint:
stage: qa
script:
- golangci-lint runWhen GitLab detects this file, it triggers the runner to execute the lint step, and any lint failures will block the merge.
Go Development Architecture Practice
Daily sharing of Golang-related technical articles, practical resources, language news, tutorials, real-world projects, and more. Looking forward to growing together. Let's go!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
