Integrate uv into your GitHub Actions workflows for fast, reliable Python dependency management and CI/CD automation.
Installation
Install latest version
Use the official astral-sh/setup-uv action:name: CI
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
Pin to specific version (recommended)
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: "0.10.8"
Setting Up Python
Using uv python install
Install Python using uv (respects project’s pinned version):
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Set up Python
run: uv python install
Using actions/setup-python
Alternatively, use GitHub’s cached Python versions:
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version-file: ".python-version"
- name: Install uv
uses: astral-sh/setup-uv@v7
Or use pyproject.toml for the latest compatible version:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version-file: "pyproject.toml"
Matrix Builds
Test across multiple Python versions:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"
steps:
- uses: actions/checkout@v6
- name: Install uv and set Python version
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --locked
- name: Run tests
run: uv run pytest
Using UV_PYTHON Environment Variable
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"
env:
UV_PYTHON: ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
Installing Dependencies
Sync project dependencies
- name: Install the project
run: uv sync --locked --all-extras
Install without dev dependencies
- name: Install the project
run: uv sync --locked --no-dev
Run tests
- name: Run tests
run: uv run pytest tests
Caching
Built-in Caching with setup-uv
The easiest approach uses the action’s built-in caching:
- name: Install uv with caching
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
Manual Caching with actions/cache
For more control, use the actions/cache action:
jobs:
test:
runs-on: ubuntu-latest
env:
UV_CACHE_DIR: /tmp/.uv-cache
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Restore uv cache
uses: actions/cache@v5
with:
path: /tmp/.uv-cache
key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
restore-keys: |
uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
uv-${{ runner.os }}
- name: Install dependencies
run: uv sync --locked
- name: Run tests
run: uv run pytest
- name: Minimize uv cache
run: uv cache prune --ci
Use uv cache prune --ci to optimize cache size. If using uv pip, replace uv.lock with requirements.txt in the cache key.
Complete CI Workflow
Here’s a complete example combining best practices:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: "0.10.8"
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --locked --all-extras
- name: Run linter
run: uv run ruff check .
- name: Run type checker
run: uv run mypy .
- name: Run tests
run: uv run pytest tests --cov
Using uv pip
If using the uv pip interface, enable system Python:
# Workflow-level
env:
UV_SYSTEM_PYTHON: 1
jobs:
test:
steps:
- name: Install dependencies
run: uv pip install -r requirements.txt
Or at the job level:
jobs:
test:
env:
UV_SYSTEM_PYTHON: 1
steps:
- name: Install dependencies
run: uv pip install -r requirements.txt
Or at the step level:
steps:
- name: Install requirements
run: uv pip install -r requirements.txt
env:
UV_SYSTEM_PYTHON: 1
Private Repositories
Access private GitHub repositories using a Personal Access Token (PAT):
Create and store PAT
Create a PAT with repository read access and add it as a repository secret (e.g., MY_PAT).
Configure Git credential helper
steps:
- name: Register personal access token
run: echo "${{ secrets.MY_PAT }}" | gh auth login --with-token
- name: Configure Git credential helper
run: gh auth setup-git
- name: Install dependencies
run: uv sync --locked
Publishing to PyPI
Publish packages using trusted publishing (no credentials needed):
Create publish workflow
name: Publish
on:
push:
tags:
- v*
jobs:
publish:
runs-on: ubuntu-latest
environment:
name: pypi
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install 3.13
- name: Build
run: uv build
- name: Test wheel
run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
- name: Test source distribution
run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
- name: Publish
run: uv publish
Configure PyPI environment
Create a pypi environment in your repository settings under Settings → Environments.
Add trusted publisher
Configure trusted publishing in your PyPI project settings, matching the workflow name, environment, and repository details.
Trigger release
git tag -a v0.1.0 -m v0.1.0
git push --tags
See astral-sh/trusted-publishing-examples for a complete working example.