⚠️ Warning: This post is over a year old. The information may be out of date.
Intro
If you program in Go, you probably have used the built-in linter, the go vet ./..., this linter is good and catches some common issues, but today we will explore some alternatives, and the chosen one was golangci-lint.
golangci-lint isn’t a linter; it is a collection of linters. Over 70 linters on it will point you from code style inconsistencies to nasty bugs.
As the name suggests, it is built to run on a continuous integration environment and is fast!
Examples of issues found
cmd/web/main.go:47:3: exitAfterDefer: os.Exit will exit, and
defer cancel()will not run (gocritic) os.Exit(1)
This one a good example that may lead to serious problems of memory leaks and resource leaks.
internal/model/user.go:15:13: G404: Use of weak random number generator (math/rand instead of crypto/rand) (gosec) number := uint(rand.Uint64())
This one is good advice to use good random number generators.
pkg/errors/errors.go:14:74:
occuredis a misspelling ofoccurred(misspell) ErrUnexpected = &Error{Code: 9999, Err: errors.New(“an unexpected error occured”)}
It is always good to fix all spelling, this tool also catches missing periods for example.
Running locally
golangci-lint, like many Go projects, is a single binary. You can download it and put it into /usr/local/bin, it is also possible to install it using brew.
There are other methods, please refer to this page to check out.
My preferred method is through Docker:
docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint golangci-lint run
Code language: JavaScript (javascript)
If you want to use all linters and possibly catch all issues, run with the flag --enable-all. Be prepared, because this tool takes serious code smell and possible sources of bugs.
Your project must have a
go.modand at least one source code, likemain.go, for the tool runs.
Using it on GitHub Action
To run in an Action on GitHub it is pretty simple, just add the contents below to a file named .github/workflows/lint.yml.
name: golangci-lint
on:
push:
tags:
- v*
branches:
- master
- main
pull_request:
permissions:
contents: read
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
- name: Checkout
uses: actions/checkout@v3
- name: Lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
Please refer to the full documentation for more details.

Conclusion
Having lint in your tool belt is always a good idea; having multiple linters is even better.
