[!NOTE] This repository uses the Aspect CLI for CI and local development. See the docs and install instructions to get started.
This ruleset integrates linting and formatting as first-class concepts under Bazel.
Features:
bazel query output.
Instead, users simply lint their existing *_library targets.sh_library targets for your shell scripts, for example.Watch Alex's talk at BazelCon 2024:
You can drive linting straight from Bazel, but the experience is rough: you
run a verbose build to produce report files, then hunt them down under
bazel-out/ and cat them yourself.
$ bazel build --config=lint --output_groups=rules_lint_human //...
INFO: Build completed successfully, 8 total actions
# ...no findings printed. Now go find and cat the reports:
$ cat bazel-out/*/bin/src/hello.AspectRulesLintShellCheck.out
In src/hello.sh line 10:
grep '*foo*' file
^-----^ SC2063 (warning): Grep uses regex, but this looks like a glob.
The Aspect CLI adds a first-class
aspect lint command that runs the same Bazel aspects, then collects and prints
every finding for you — grouped by linter, tagged by severity, with file:line
and rule, and one-key interactive fixes:
$ aspect lint //...
🧹 Linters (1): ShellCheck
Lint findings
ℹ️ src/hello.sh:4 · ShellCheck — Double quote to prevent globbing and word splitting.
⚠️ src/hello.sh:10 · ShellCheck — Grep uses regex, but this looks like a glob.
It also scopes findings to your changed lines by default (the "Water Leak
Principle") and applies fixes with aspect lint --fix.
On CI, the free Aspect Workflows GitHub App
makes this shine: every aspect lint task posts a rich GitHub status check
— findings grouped by linter and severity with file:line and rule, a
per-linter summary table, and a copy-paste reproduce command — and surfaces the
same findings as inline PR review comments. Install and authenticate it in a few
minutes; no server to run.
The screenshot above is a live status check from this repo's
examples/pythonlint task — open the real thing.
Configure it once in .aspect/config.axl by pointing the lint task at your
aspects — no --config=lint or output-group flags to remember:
def config(ctx: ConfigContext):
ctx.tasks["lint"].args.aspects = ["//tools/lint:linters.bzl%shellcheck"]
Try it in this repo: every linter under examples/ is wired
up for aspect lint. After installing the CLI:
$ cd examples/shell && aspect lint //...
The same applies to formatting. Instead of bazel run //tools/format, the
aspect format command runs your //tools/format target, formats only your
changed files by default (or --scope=all for the whole tree), and reports
exactly what it touched — with a ready-to-run fix command:
$ aspect format
→ ✨ Format · Formatting changed files
→ 📋 Diff · Computing format diff
2 files were modified:
- src/hello.sh
- src/sourced_dep.sh
On CI it posts a format status check via the same GitHub App, and
--severity chooses whether an unformatted file warns or fails the build. It
works out of the box — aspect format already targets //tools/format, so no
extra config is needed:
$ cd examples/shell && aspect format
See the Aspect CLI overview and the
lint and
format task docs.
New tools are being added frequently, so check this page again!
Linters which are not language-specific:
| Language | Formatter | Linter(s) |
|---|---|---|
| C / C++ | clang-format | clang-tidy or cppcheck |
| CUE | cue fmt | |
| Cuda | clang-format | |
| CSS, Less, Sass | Prettier | Stylelint |
| F# | Fantomas | |
| Go | gofmt or gofumpt | |
| Go Module | modfmt | |
| Gherkin | prettier-plugin-gherkin | |
| GraphQL | Prettier | |
| HCL (Hashicorp Config) | terraform fmt | |
| HTML | Prettier | |
| JSON | Prettier | |
| Java | google-java-format | pmd , Checkstyle, Spotbugs |
| JavaScript | Prettier | ESLint |
| HTML templates | djlint | |
| Jsonnet | jsonnetfmt | |
| Kotlin | ktfmt | ktlint |
| Markdown | Prettier | Vale |
| Pkl | pkl | |
| Protocol Buffer | buf | buf lint |
| Python | ruff | bandit, flake8, pydoclint, pylint, ruff, ty |
| QML | qmlformat | qmllint |
| Ruby | RuboCop, Standard | |
| Rust | rustfmt | clippy |
| SQL | prettier-plugin-sql | |
| Scala | scalafmt | scalafix |
| Shell | shfmt | shellcheck |
| Starlark | Buildifier | Buildifier |
| Swift | SwiftFormat (1) | |
| TOML | taplo | |
| TSX | Prettier | ESLint |
| TypeScript | Prettier | ESLint |
| YAML | yamlfmt | yamllint |
| XML | prettier/plugin-xml |
To add a tool, please follow the steps in lint/README.md or format/README.md and then send us a PR. Thanks!!
Follow instructions from the release you wish to use: https://github.com/aspect-build/rules_lint/releases
Formatting and Linting are inherently different, which leads to differences in how they are used in rules_lint. It is best conceived as two rulesets in one.
| Formatter | Linter |
|---|---|
| Only one per language, since they could conflict with each other. | Many per language is fine; results compose. |
| Invariant: program's behavior is never changed. | Suggested fixes may change behavior. |
| Developer has no choices. Always blindly accept result. | Fix may be manual, or select from multiple auto-fixes. |
| Changes must be applied. | Violations can be suppressed. |
| Operates on a single file at a time. | Can require the dependency graph. |
| Can always format just changed files / regions | New violations might be introduced in unchanged files. |
| Fast enough to put in a pre-commit workflow. | Some are slow. |
To format files, run the target you create when you install rules_lint.
We recommend using a Git pre-commit hook to format changed files, and Aspect Workflows to provide the check on CI.
See Formatting for more ways to use the formatter.
Also see API Documentation
Demo:
To lint code, we recommend using the Aspect CLI to get the missing lint command, and Aspect Workflows to provide first-class support for "linters as code reviewers".
For example, running bazel lint //src:all prints lint warnings to the terminal for all targets in the //src package.
Suggested fixes from the linter tools are presented interactively.
See Linting for more ways to use the linter.
Also see API Documentation
Demo:
The linters only visit files that are part of the Bazel dependency graph (listed as srcs to some library target).
The formatter honors the .gitignore and .gitattributes files.
Otherwise use the affordance provided by the tool, for example .prettierignore for files to be ignored by Prettier.
Sometimes engineers want to ignore a file with a certain extension because the content isn't actually valid syntax for the corresponding language.
For example, you might write a template for YAML and name it my-template.yaml even though it needs to have some interpolated values inserted before it's syntactically valid.
We recommend instead fixing the file extension. In this example, my.yaml.tmpl or my-template.yaml_ might be better.
We believe that existing editor plugins should just work as-is. They may download or bundle their own copy of the tools, which can lead to some version skew in lint/format rules.
For formatting, we believe it's a waste of time to configure these in the editor, because developers should just rely on formatting happening when they commit and not care what the code looks like before that point. But we're not trying to stop anyone, either!
You could probably configure the editor to always run the same Bazel command, any time a file is changed. Instructions to do this are out-of-scope for this repo, particularly since they have to be formulated and updated for so many editors.
This ruleset collects limited usage data via tools_telemetry, which is reported to Aspect Build Inc and governed by our privacy policy.
2.7.2 +8d2026-06-24 | |
2.7.1 +21h2026-06-16 | |
2.7.0 +24d2026-06-15 | |
2.5.2 +27d2026-05-05 | |
2.0.0 +2d2026-01-26 | |
2.0.0-rc1 +10d2026-01-23 | |
2.0.0-rc0 +11d2026-01-13 | |
2.0.0-beta.0 +23h2025-12-23 | |
1.12.0 +1d2025-12-22 | |
1.11.0 +3d2025-12-20 | |
1.10.1 +6d2025-10-14 | |
1.9.1 +11d2025-10-07 | |
1.9.0 +22d2025-09-26 | |
1.7.0 +9d2025-09-03 | |
1.6.0 +10d2025-08-25 | |
1.5.1 +3d2025-07-15 | |
1.5.0 +<1h2025-07-11 | |
1.4.5 +1.4mo2025-07-11 | |
1.4.4 +15d2025-05-28 | |
1.4.2 +22h2025-05-13 | |
1.4.0 +18d2025-05-12 | |
1.3.5 +12d2025-04-24 | |
1.3.4 +8d2025-04-11 | |
1.3.1 +28d2025-04-03 | |
1.2.0 +10d2025-02-14 | |
1.0.9 +1.2mo2025-01-24 | |
1.0.8 +9d2024-12-18 | |
1.0.7 +5d2024-12-09 | |
1.0.6 +1.3mo2024-12-03 | |
1.0.3 +20d2024-10-25 | |
1.0.1 +3d2024-09-10 | |
1.0.0 +9d2024-09-07 | |
1.0.0-rc8 +19d2024-08-06 | |
1.0.0-rc6 +12d2024-07-17 | |
1.0.0-rc5 +18d2024-07-05 | |
1.0.0-rc3 +<1h2024-05-31 | |
1.0.0-rc2 +8d2024-05-31 | |
1.0.0-rc1 +3h2024-05-23 | |
1.0.0-rc0 +11d2024-05-22 | |
0.20.0 +16d2024-05-10 | |
0.19.0 +14d2024-04-24 | |
0.18.0 +6h2024-04-09 | |
0.17.0 +23h2024-04-09 | |
0.16.0 +11d2024-04-08 | |
0.15.0 +13d2024-03-28 | |
0.14.2 +8h2024-03-14 | |
0.14.1 +1d2024-03-14 | |
0.14.0 +7d2024-03-12 | |
0.13.0 +24d2024-03-05 | |
0.11.1 +9d2024-02-08 | |
0.10.0 +10d2024-01-22 | |
0.8.0 +28d2024-01-04 | |
0.6.1 +5d2023-12-06 | |
0.6.0 +1.3mo2023-11-30 | |
0.4.0 +1h2023-10-20 | |
0.3.0 +2d2023-10-20 | |
0.2.1 +21h2023-10-17 | |
0.2.0 +8h2023-10-17 | |
0.1.22023-10-16 |