Skip to main content
Formatting and linting are common tasks that involve the build system. We can run these with Bazel. We’ll use Aspect’s https://registry.bazel.build/modules/aspect_rules_lint to make this more ergonomic.

Formatting

The go CLI comes with the fmt command, applying an opinionated formatting to all Go code. There’s also a stricter alternative, https://pkg.go.dev/mvdan.cc/gofumpt which we’ll use in this lesson. The Aspect CLI’s format task formats all files from the repository root. First make sure there’s a git repository (you may need to run git init) since the formatter only looks at version-controlled files by default.
With the tools/bazel wrapper installed, your team can keep typing bazel format and Bazelisk routes it through the Aspect CLI. Without the CLI you can still run the underlying formatter target directly with bazel run //tools/format.
However developers won’t remember to run this command, so we have https://pre-commit.com/ setup to automatically format code when you git commit. Note that each developer must do a one-time setup in the repository to enable the git pre-commit hook. If you setup a CI check that requires code be formatted, you can point to the pre-commit setup instructions from the failure message you print, making this easily discoverable.
Curious how the formatter knows which tool to run? You can use bazel query commands to inspect the setup:

Linting

There are a variety of popular Go linting tools, such as nogo, govet, revive, and many more. There are so many there’s an “aggregator” linter to combine them: https://golangci-lint.run/usage/linters/ As of January 2025, rules_lint doesn’t have any Go linters included. So our repository follows the setup from rules_go instead: https://github.com/bazel-contrib/rules_go/blob/master/docs/go/core/bzlmod.md#configuring-nogo This integrates as a Bazel “validation action”. This special type of build action is spawned even though it doesn’t produce any needed outputs, and there is one for each go_library target. Thus we can check that linting is working just by introducing a violation, for example by shadowing a variable. Try changing the body of our HelloServer function in cmd/hello/main.go to have this code:
Now if we try to build the library, we should get an error:
It’s possible to skip these validation actions with --norun_validations