uv Managed Python and UV_PYTHON_DOWNLOADS
uv can manage its own standalone Python interpreters, controlled by UV_PYTHON_DOWNLOADS and UV_PYTHON, instead of relying on a system Python.
Managed Python is what lets uv work on a bare runner. Understanding when uv downloads an interpreter, and how to force system Python, prevents surprising CI behavior.
What it does
By default uv prefers managed standalone interpreters and downloads a missing one automatically when a project needs it. UV_PYTHON_DOWNLOADS controls that (automatic, manual, or never), UV_PYTHON forces a specific interpreter, and --python-preference chooses between system and managed builds.
Common usage
UV_PYTHON=3.12 uv sync
UV_PYTHON_DOWNLOADS=never uv sync
uv sync --python-preference only-system
uv sync --python-preference only-managed
uv python list --only-installedOptions
| Setting | What it does |
|---|---|
| UV_PYTHON_DOWNLOADS | automatic, manual, or never for auto-downloads |
| UV_PYTHON | Force a specific interpreter version or path |
| --python-preference | only-system, only-managed, system, or managed |
| UV_PYTHON_INSTALL_DIR | Where managed interpreters are installed |
In CI
On runners that already have the right Python, set UV_PYTHON_DOWNLOADS=never and --python-preference only-system to avoid surprise downloads. On bare runners, let uv download managed Python and cache UV_PYTHON_INSTALL_DIR so interpreters persist across runs. Pin the version via .python-version or UV_PYTHON for determinism.
Common errors in CI
"error: No interpreter found for Python <version> in managed installations or search path" with UV_PYTHON_DOWNLOADS=never means downloads are off and no matching interpreter exists; install one or allow downloads. only-system on a runner without that version fails the same way. An unexpected download in a job usually means UV_PYTHON_DOWNLOADS was left at automatic.