blob: 45459fe84a33ac4b2dbaba4b5e6e6c8b474336da [file] [edit]
---
title: Bazel Integration
slug: /bazel
description: Run Pyrefly type checking over Bazel Python targets with rules_pyrefly
---
{/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/}
# Bazel Integration
The Bazel integration requires Pyrefly 1.2 or later and uses the
`pyrefly bazel-check` subcommand with the companion ruleset
[`rules_pyrefly`](https://github.com/facebook/rules_pyrefly) (available via the
[Bazel Central Registry](https://registry.bazel.build/modules/rules_pyrefly); check
there for the latest version).
Instead of writing custom build logic to collect sources, dependencies, import
paths, and generated files, you can apply Pyrefly as a Bazel
[aspect](https://bazel.build/extending/aspects) over existing `py_library`,
`py_binary`, and `py_test` targets.
:::info Under active development
`pyrefly bazel-check` and the `rules_pyrefly` Starlark API are under active
development and may still see breaking changes in minor `rules_pyrefly` releases
before they stabilize. Please try the integration and report any problems in the
appropriate repository. See
[`rules_pyrefly` releases](https://github.com/facebook/rules_pyrefly/releases) and
[`pyrefly/private/versions.bzl`](https://github.com/facebook/rules_pyrefly/blob/main/pyrefly/private/versions.bzl)
for the currently supported Pyrefly version(s).
:::
## When to use it
- Your Python code is already built with [`rules_python`](https://github.com/bazelbuild/rules_python) and you want `bazel build` to also type-check it.
- You want one pinned Pyrefly version per repository, resolved hermetically through a Bzlmod toolchain, with no per-`BUILD` file boilerplate.
If you do not use Bazel, use [`pyrefly check`](./configuration.mdx) as before. The Bazel integration does not read `pyrefly.toml`; checking policy is configured on the aspect.
## Setup
### 1. Add the dependency and register a toolchain
This guide assumes your root `MODULE.bazel` already declares `rules_python`. Keep
that existing `bazel_dep` unchanged; adding a second declaration causes an error.
Choose each version independently:
- `RULES_PYREFLY_VERSION`: the latest compatible
[`rules_pyrefly` release](https://registry.bazel.build/modules/rules_pyrefly).
- `PYREFLY_VERSION`: a version listed in
[`pyrefly/private/versions.bzl`](https://github.com/facebook/rules_pyrefly/blob/main/pyrefly/private/versions.bzl).
Replace the uppercase placeholders below in your root `MODULE.bazel`:
```starlark
bazel_dep(name = "rules_pyrefly", version = "RULES_PYREFLY_VERSION")
pyrefly = use_extension("@rules_pyrefly//pyrefly:extensions.bzl", "pyrefly")
pyrefly.toolchain(version = "PYREFLY_VERSION")
use_repo(pyrefly, "pyrefly_toolchains")
register_toolchains("@pyrefly_toolchains//:all")
```
For forks, mirrors, or prereleases that are not in the checked-in release
metadata, `pyrefly.toolchain` also accepts `base_url` + `sha256` see the
[`rules_pyrefly` README](https://github.com/facebook/rules_pyrefly#configuration)
for that form.
### 2. Define an aspect
The aspect can live in any `.bzl` file in a Bazel package. This example creates an
empty `tools/BUILD.bazel` so Bazel recognizes `//tools` as a package, then exports
the aspect from `tools/aspects.bzl`:
```starlark
# tools/aspects.bzl
load("@rules_pyrefly//pyrefly:pyrefly.bzl", "pyrefly")
pyrefly_aspect = pyrefly()
```
If you choose another location, update the `--aspects` label in the next step to
match.
With no arguments the aspect infers the Python version from the
`rules_python` toolchain and the platform from Bazel platform constraints. For
the full set of overrides, see the [`rules_pyrefly` README](https://github.com/facebook/rules_pyrefly#configuration).
### 3. Wire it in `.bazelrc`
```text
# .bazelrc
build:pyrefly --aspects=//tools:aspects.bzl%pyrefly_aspect
build:pyrefly --output_groups=pyrefly
```
`--output_groups=pyrefly` is a type-check-only build. Use
`--output_groups=+pyrefly` only when you also want the normal target outputs.
### 4. Run
```shell
# one package
bazel build --config=pyrefly //path/to/package:target
# whole repo (with --keep_going to collect all findings in one pass)
bazel build --config=pyrefly --keep_going //...
```
Diagnostics are printed to Bazel's stderr, and `error`-severity findings fail the
action. The [`rules_pyrefly` aspect configuration](https://github.com/facebook/rules_pyrefly#configuration)
controls the minimum severity; at its default `error` threshold, lower-severity
findings are omitted from both stderr and the per-target JSON. The minimum-severity
filter does not remove `reveal_type()` output. The JSON diagnostics are available in
the `pyrefly` output group, and the generated input JSON is available in the
debug-only `pyrefly_input` output group.
## How it works
Each eligible Python target gets one `pyrefly bazel-check` action that checks
the target's own sources (from `PyInfo`) with its dependencies available for
import resolution. Implementation details, including target selection, check roots,
search-path facts, path overlays for generated files, output groups, and the
JSON contract, live in [`rules_pyrefly` docs/integration.md](https://github.com/facebook/rules_pyrefly/blob/main/docs/integration.md) and the
Pyrefly-side parser in [`pyrefly/lib/commands/bazel_check.rs`](https://github.com/facebook/pyrefly/blob/main/pyrefly/lib/commands/bazel_check.rs).
For design tradeoffs and rationales, see
[`rules_pyrefly` docs/design.md](https://github.com/facebook/rules_pyrefly/blob/main/docs/design.md) and
[`docs/users.md`](https://github.com/facebook/rules_pyrefly/blob/main/docs/users.md).