Skip to content

How to change the Python version of a uv project

uv

To change the Python version of a uv project, run uv python pin 3.12 to update .python-version, then uv sync to rebuild the virtual environment against the new interpreter. If you also want to change which versions the project supports, edit requires-python in pyproject.toml and run uv lock && uv sync.

A uv project tracks Python versions in two places: the .python-version file pins the development interpreter (e.g., 3.12), and requires-python in pyproject.toml declares which versions the project supports (e.g., >=3.11). The pinned version must satisfy the requires-python constraint, or uv will report an incompatibility error.

See what Python versions are available

Before you switch or upgrade, check what uv can install:

$ uv python list

This shows every CPython and PyPy build uv can download, along with the interpreters already on your system. Pick a version from this list.

Pin a different development interpreter

$ uv python pin 3.12

This writes 3.12 to .python-version, which uv reads on every command.

Then re-sync so the virtual environment picks up the new interpreter:

$ uv sync

If 3.12 isn’t already installed, uv downloads it during the sync. uv sync recreates .venv against the pinned version when the interpreter changes, so you usually don’t need to delete the virtual environment by hand. If a sync fails partway through or the venv ends up in an inconsistent state, force a clean rebuild:

$ uv venv --python 3.12 --clear
$ uv sync

Upgrade a patch release or switch the minor version

uv handles patch upgrades and minor-version changes differently, and mixing them up is the usual source of confusion about “changing” a project’s Python.

uv python pin 3.12 records a loose request for any 3.12.x. A sync then uses the newest 3.12.x already installed on your machine (for example, 3.12.13); it does not download a newer patch on its own. Because the pin isn’t tied to one patch, you don’t re-pin to move within 3.12.

To fetch a newer patch, upgrade the interpreter, then sync:

$ uv python upgrade 3.12
$ uv sync

uv python upgrade downloads the latest patch (3.12.13 to 3.12.14); the loose 3.12 pin accepts it on the next sync with no re-pin, because a patch bump doesn’t change the language version your dependencies resolve against. See how to keep Python up to date with uv python upgrade for the full workflow.

Changing the minor version is always explicit. Re-pin with uv python pin 3.13, then run uv sync. uv never crosses minor versions on its own, because a minor bump can change which dependency versions resolve.

To pin one exact patch and stop tracking the latest, pin the full version:

$ uv python pin 3.12.8

Change the supported Python versions

Edit requires-python in pyproject.toml:

[project]
requires-python = ">=3.11"

Then regenerate the lockfile and re-sync:

$ uv lock
$ uv sync

uv lock re-resolves all dependencies against the new constraint. uv sync updates the virtual environment to match.

Tip

Raising the minimum Python version can unlock newer dependencies and drop compatibility workarounds, but it excludes users on older interpreters.

Use a different version for a single command

--python selects which interpreter to use for a single invocation, overriding the .python-version pin. The flag works on most uv commands, not just uv run:

$ uv run --python 3.10 python -c "import sys; print(sys.version)"
$ uv sync --python 3.13
$ uv add --python 3.13 httpx

This is useful for quick compatibility checks without editing project files.

Keep CI on the same Python version

CI systems and Docker images should honor the same .python-version pin so local and remote builds agree. In GitHub Actions, install uv with astral-sh/setup-uv and then let uv sync install the pinned interpreter on demand, or call uv python install explicitly. In Docker, copy the .python-version file into the image before running uv sync so the build uses the same pinned Python version as local development. See how to install Python with uv for interpreter management details.

Frequently asked questions

Do I need to delete .venv when switching Python versions?

No. uv sync rebuilds the virtual environment against the pinned interpreter. Only use uv venv --clear if a sync fails partway through or the venv gets into an inconsistent state.

Does changing the Python version break my lockfile?

Usually not. uv.lock is resolved against requires-python, not the pinned development version. Changing .python-version inside that range leaves the lockfile valid. Editing requires-python itself triggers a re-resolve on the next uv lock.

What if the Python version isn’t installed on my machine?

uv downloads managed Python builds on demand: running uv sync or uv run with a version that isn’t installed will fetch it automatically the first time it’s needed. To install a specific version up front, run uv python install 3.13.

How do I downgrade the Python version with uv?

Pin the older minor version with uv python pin 3.10, then run uv sync. The pin must still satisfy requires-python in pyproject.toml; if the downgrade falls below your current minimum, lower the floor there (for example to >=3.10) and run uv lock first.

Related

This handbook is free, independent, and ad-free. If it saved you time, consider sponsoring it on GitHub.

Last updated on