uv/docs/guides/integration/github.md
Zanie Blue b6b7409d13
Some checks are pending
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / check system | alpine (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | pyodide on ubuntu (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | registries (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
Bump version to 0.7.16 (#14334)
2025-06-27 16:46:36 -05:00

9.6 KiB

title description
Using uv in GitHub Actions A guide to using uv in GitHub Actions, including installation, setting up Python, installing dependencies, and more.

Using uv in GitHub Actions

Installation

For use with GitHub Actions, we recommend the official astral-sh/setup-uv action, which installs uv, adds it to PATH, (optionally) persists the cache, and more, with support for all uv-supported platforms.

To install the latest version of uv:

name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

It is considered best practice to pin to a specific uv version, e.g., with:

name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5
        with:
          # Install a specific version of uv.
          version: "0.7.16"

Setting up Python

Python can be installed with the python install command:

name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

      - name: Set up Python
        run: uv python install

This will respect the Python version pinned in the project.

Alternatively, the official GitHub setup-python action can be used. This can be faster, because GitHub caches the Python versions alongside the runner.

Set the python-version-file option to use the pinned version for the project:

name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

      - name: "Set up Python"
        uses: actions/setup-python@v5
        with:
          python-version-file: ".python-version"

Or, specify the pyproject.toml file to ignore the pin and use the latest version compatible with the project's requires-python constraint:

name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

      - name: "Set up Python"
        uses: actions/setup-python@v5
        with:
          python-version-file: "pyproject.toml"

Multiple Python versions

When using a matrix to test multiple Python versions, set the Python version using astral-sh/setup-uv, which will override the Python version specification in the pyproject.toml or .python-version files:

jobs:
  build:
    name: continuous-integration
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"

    steps:
      - uses: actions/checkout@v4

      - name: Install uv and set the python version
        uses: astral-sh/setup-uv@v5
        with:
          python-version: ${{ matrix.python-version }}

If not using the setup-uv action, you can set the UV_PYTHON environment variable:

jobs:
  build:
    name: continuous-integration
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"
    env:
      UV_PYTHON: ${{ matrix.python-version }}
    steps:
      - uses: actions/checkout@v4

Syncing and running

Once uv and Python are installed, the project can be installed with uv sync and commands can be run in the environment with uv run:

name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

      - name: Install the project
        run: uv sync --locked --all-extras --dev

      - name: Run tests
        # For example, using `pytest`
        run: uv run pytest tests

!!! tip

The
[`UV_PROJECT_ENVIRONMENT` setting](../../concepts/projects/config.md#project-environment-path) can
be used to install to the system Python environment instead of creating a virtual environment.

Caching

It may improve CI times to store uv's cache across workflow runs.

The astral-sh/setup-uv has built-in support for persisting the cache:

- name: Enable caching
  uses: astral-sh/setup-uv@v5
  with:
    enable-cache: true

You can configure the action to use a custom cache directory on the runner:

- name: Define a custom uv cache path
  uses: astral-sh/setup-uv@v5
  with:
    enable-cache: true
    cache-local-path: "/path/to/cache"

Or invalidate it when the lockfile changes:

- name: Define a cache dependency glob
  uses: astral-sh/setup-uv@v5
  with:
    enable-cache: true
    cache-dependency-glob: "uv.lock"

Or when any requirements file changes:

- name: Define a cache dependency glob
  uses: astral-sh/setup-uv@v5
  with:
    enable-cache: true
    cache-dependency-glob: "requirements**.txt"

Note that astral-sh/setup-uv will automatically use a separate cache key for each host architecture and platform.

Alternatively, you can manage the cache manually with the actions/cache action:

jobs:
  install_job:
    env:
      # Configure a constant location for the uv cache
      UV_CACHE_DIR: /tmp/.uv-cache

    steps:
      # ... setup up Python and uv ...

      - name: Restore uv cache
        uses: actions/cache@v4
        with:
          path: /tmp/.uv-cache
          key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
          restore-keys: |
            uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
            uv-${{ runner.os }}

      # ... install packages, run tests, etc ...

      - name: Minimize uv cache
        run: uv cache prune --ci

The uv cache prune --ci command is used to reduce the size of the cache and is optimized for CI. Its effect on performance is dependent on the packages being installed.

!!! tip

If using `uv pip`, use `requirements.txt` instead of `uv.lock` in the cache key.

!!! note

[post-job-hook]: https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/running-scripts-before-or-after-a-job

When using non-ephemeral, self-hosted runners the default cache directory can grow unbounded.
In this case, it may not be optimal to share the cache between jobs. Instead, move the cache
inside the GitHub Workspace and remove it once the job finishes using a
[Post Job Hook][post-job-hook].

```yaml
install_job:
  env:
    # Configure a relative location for the uv cache
    UV_CACHE_DIR: ${{ github.workspace }}/.cache/uv
```

Using a post job hook requires setting the `ACTIONS_RUNNER_HOOK_JOB_STARTED` environment
variable on the self-hosted runner to the path of a cleanup script such as the one shown below.

```sh title="clean-uv-cache.sh"
#!/usr/bin/env sh
uv cache clean
```

Using uv pip

If using the uv pip interface instead of the uv project interface, uv requires a virtual environment by default. To allow installing packages into the system environment, use the --system flag on all uv invocations or set the UV_SYSTEM_PYTHON variable.

The UV_SYSTEM_PYTHON variable can be defined in at different scopes.

Opt-in for the entire workflow by defining it at the top level:

env:
  UV_SYSTEM_PYTHON: 1

jobs: ...

Or, opt-in for a specific job in the workflow:

jobs:
  install_job:
    env:
      UV_SYSTEM_PYTHON: 1
    ...

Or, opt-in for a specific step in a job:

steps:
  - name: Install requirements
    run: uv pip install -r requirements.txt
    env:
      UV_SYSTEM_PYTHON: 1

To opt-out again, the --no-system flag can be used in any uv invocation.

Private repos

If your project has dependencies on private GitHub repositories, you will need to configure a personal access token (PAT) to allow uv to fetch them.

After creating a PAT that has read access to the private repositories, add it as a repository secret.

Then, you can use the gh CLI (which is installed in GitHub Actions runners by default) to configure a credential helper for Git to use the PAT for queries to repositories hosted on github.com.

For example, if you called your repository secret MY_PAT:

steps:
  - name: Register the personal access token
    run: echo "${{ secrets.MY_PAT }}" | gh auth login --with-token
  - name: Configure the Git credential helper
    run: gh auth setup-git