> ## Documentation Index
> Fetch the complete documentation index at: https://site.aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Python with Bazel

> Build, test, and containerize Python projects with Bazel using aspect_rules_py, rules_python, uv lockfiles, and hermetic python-build-standalone interpreters.

`aspect_rules_py` is a layer on top of the community
[rules\_python](https://github.com/bazel-contrib/rules_python) ruleset that
replaces the end-user rules `py_library`, `py_binary`, and `py_test` with
implementations that behave more like standard Python tooling. It pairs with
[uv](https://github.com/astral-sh/uv) for fast, reproducible dependency
management and cross-platform container builds.

<Tip>
  Stuck?

  * Check for [known issues](https://github.com/aspect-build/rules_py/issues)
  * Ask in `#python` on [Bazel Slack](http://slack.bazel.build)
  * Sign up for [commercial support](/services), provided by Aspect as a shared Slack channel.
</Tip>

## Create a new project

<Steps>
  <Step title="Install the Aspect CLI">
    ```bash theme={null}
    brew install aspect-build/aspect/aspect
    ```

    For other installation methods, see [Aspect CLI](/docs/cli). `aspect init` requires CLI v2026.25.11 or newer.
  </Step>

  <Step title="Scaffold a new project">
    ```bash theme={null}
    aspect init my-app --preset py && cd my-app
    ```

    A working Bazel + Python setup with `uv` for dependency management, Gazelle for BUILD file generation, and `ruff` for linting. See [`aspect init`](/docs/cli/tasks/init) for the full flag reference (presets, `--template`, `--license`).

    Prefer GitHub's "Use this template" button? Start from [aspect-starters/py](https://github.com/aspect-starters/py) instead, or `git clone https://github.com/aspect-starters/py my-app`.
  </Step>

  <Step title="Set up your dev environment">
    ```bash theme={null}
    direnv allow
    ```

    Follow the prompts to run `bazel run //tools:bazel_env`, which installs project tools to your PATH. [direnv](https://direnv.net) is optional but recommended; without it you have to install tools yourself.
  </Step>

  <Step title="Add a dependency">
    Add packages to `pyproject.toml`, then update the lockfile:

    ```bash theme={null}
    uv add requests
    ./tools/repin
    ```
  </Step>

  <Step title="Generate BUILD files and run">
    ```bash theme={null}
    aspect gazelle      # generate BUILD files from your source
    bazel run //app:app    # run your app
    bazel test //...       # run all tests
    ```
  </Step>
</Steps>

## Explore Bazel with Python

<Columns cols={2}>
  <Card title="Starter Template" icon="clone" href="https://github.com/aspect-starters/py">
    If you just want the code, clone the starter repository and explore a working Bazel + Python setup immediately.

    Use GitHub's Codespace for an instant playground.
  </Card>

  <Card title="Bazel 102: Python Training" icon="graduation-cap" href="/learning/bazel-102">
    A hands-on course for building, testing, and shipping Python with Bazel.

    Covers dependency pinning, virtualenvs, pytest, linting, and container images.
  </Card>
</Columns>

## Key features

* **Idiomatic Python behavior.** Uses the standard `site-packages` folder
  layout instead of manipulating `$PYTHONPATH`, so your code behaves the
  same way under Bazel as it does in a normal Python environment.
* **Real virtualenvs.** Each build runs in a virtualenv, which means IDE
  support (autocomplete, jump-to-definition) works in PyCharm, VS Code, and
  others without extra configuration.
* **Truly hermetic.** The launcher uses Bash rather than Python, so there's
  no dependency on a system Python interpreter, even when using a hermetic
  toolchain.
* **Truly cross-platform.** Build Linux container images from Mac. Build
  Windows-compatible binaries from Linux. Build across architectures and
  target custom platforms with ease.
* **uv instead of pip.** One `uv.lock` file replaces per-platform
  `requirements.txt` files and works with private package registries out of the box.

## Ecosystem

<Columns cols={2}>
  <Card title="Manage dependencies with uv" icon="lock" href="/docs/bazel/python/uv">
    One lockfile for all platforms. Fast, reproducible installs and cross-platform container builds.
  </Card>

  <Card title="Migrating from rules_python" icon="arrow-right-arrow-left" href="/docs/bazel/python/migrating">
    Already using rules\_python? Migration is mostly a drop-in replacement.
  </Card>
</Columns>

<Columns cols={1}>
  <Card title="Video: Python at Monorepo World" icon="video" href="https://www.youtube.com/watch?v=en3ep4rw0oA">
    Watch Alex Eagle's talk for a quick demo of how rules\_py makes Python
    with Bazel easy.
  </Card>
</Columns>

## Package management with PyPI

Use `pyproject.toml` to declare direct dependencies. Use `uv` to pin the dependency versions in a `uv.lock` file.
This aligns Bazel builds with standard Python packaging while preserving hermetic, reproducible resolution.

`rules_uv` and `pip_compile` targets update lockfiles, and `pip.parse` in `MODULE.bazel` exposes packages to Bazel targets.

<Tip>
  After changing dependencies, repin before building. In the starter template, run `./tools/repin` to update runtime requirements, transitive locks, and the Gazelle Python manifest together.
</Tip>

Quickstart:

* Create `app/__main__.py` with a simple program (for example importing `requests`).
* Add dependencies in `pyproject.toml`, then run `./tools/repin` to refresh pinned requirements and manifests.
* Run `aspect gazelle` to generate `BUILD` files, then `bazel run //app:app_bin` to execute the binary.

## Python programs

Generate `BUILD` files with Gazelle, then use `py_library`, `py_binary`, and `py_test` for code organization, executables, and tests.
Bazel runs these targets with a hermetic Python toolchain instead of relying on a system interpreter.

**API reference:**
[Python rules](/bazel/python/aspect_rules_py/py_defs) |
[toolchains](/bazel/python/aspect_rules_py/py_toolchains) |
[repositories](/bazel/python/aspect_rules_py/py_repositories)

## Developer workflow

For day-to-day development, Bazel-generated virtualenv targets improve editor integration and local debugging while staying aligned with Bazel's dependency graph.

* [Editor features: virtualenvs](/learning/bazel-102/virtualenvs)
* [Testing and Debugging](/learning/bazel-102/test-and-debug)
* [Watch mode](/learning/bazel-102/watch-mode)

## Monorepo dependencies

In a live-at-HEAD monorepo workflow, local libraries and services can be consumed directly without publishing intermediate package versions.
Layered requirements and regular lockfile regeneration keep dependency resolution consistent across all packages.

Typical flow:

* Scaffold the new library/service in-repo, then add its requirements file into `requirements/all.in`.
* Update Bazel inputs for dependency compilation (for example add new requirement files to `requirements/BUILD` data).
* Run `./tools/repin` and `aspect gazelle`, then import and use the new package directly from application code.

## Code generation and tools

Python console scripts can be exposed as Bazel tools and invoked from build actions.
Use `py_console_script_binary` and `run_binary` to model code generation with explicit inputs and outputs.

**Course:**
[Integrate Python console scripts as tools](/learning/bazel-102/console-scripts)

## Shipping artifacts

Bazel can package Python applications into OCI images and load them locally for quick verification.
For release pipelines, stamping can embed build metadata in otherwise deterministic outputs.

**Course:**
[Shipping artifacts](/learning/bazel-102/ship-artifacts)

## Cross-builds

Cross-build scenarios require careful handling of host, exec, and target platforms, especially when dependencies include non-pure Python wheels or source builds.

**Course:**
[Cross-builds](/learning/bazel-102/crossbuilds)

## Formatting and linting

The starter workflow follows a simple two-step loop:

1. Format tracked files:
   ```bash theme={null}
   aspect format
   ```
2. Run lint checks (and apply safe fixes when offered):
   ```bash theme={null}
   aspect lint app/...
   ```

Configure tool behavior in `pyproject.toml` and keep linting in CI so style and correctness checks stay consistent across the team.

**API reference:**

* [ruff](/bazel/python/aspect_rules_lint/lint_ruff) - Ruff linter integration. [Homepage](https://docs.astral.sh/ruff/).
* [ty](/bazel/python/aspect_rules_lint/lint_ty) - Ty type-checking integration. [Homepage](https://docs.astral.sh/ty/).
* [flake8](/bazel/python/aspect_rules_lint/lint_flake8) - Flake8 linter integration. [Homepage](https://flake8.pycqa.org/).
* [pylint](/bazel/python/aspect_rules_lint/lint_pylint) - Pylint linter integration. [Homepage](https://pylint.pycqa.org/).

### Additional APIs

* [unstable APIs](/bazel/python/aspect_rules_py/py_unstable_defs) - Experimental or evolving interfaces.
