# How to keep Python up to date with uv python upgrade

Run `uv python upgrade` to pull the latest patch release for every Python that [uv](https://pydevtools.com/handbook/reference/uv.md) manages. Pass a minor version (`uv python upgrade 3.12`) to scope the upgrade to one line. [Virtual environments](https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment.md) created from a minor-version pin follow the new patch automatically.

This keeps uv-managed CPython installs current with security and bug-fix releases. It does not touch [system Python](https://pydevtools.com/handbook/explanation/why-should-i-avoid-system-python.md) or interpreters installed by [Homebrew](https://pydevtools.com/handbook/reference/homebrew.md) or [pyenv](https://pydevtools.com/handbook/reference/pyenv.md). For installing a new minor version or switching a project, see [how to install Python with uv](https://pydevtools.com/handbook/how-to/how-to-install-python-with-uv.md) and [how to change the Python version of a uv project](https://pydevtools.com/handbook/how-to/how-to-change-the-python-version-of-a-uv-project.md).

## Pull the latest patch for every installed minor version

```console
$ uv python upgrade
```

If everything is current, uv prints:

```
All versions already on latest supported patch release
```

If a newer patch exists for one or more installed minor versions, uv downloads and installs each:

```
Downloading cpython-3.11.15-x86_64-unknown-linux-gnu (download) (29.9MiB)
 Downloaded cpython-3.11.15-x86_64-unknown-linux-gnu (download)
Installed Python 3.11.15 in 1.70s
 + cpython-3.11.15-x86_64-unknown-linux-gnu
```

The previous patch directory is retained alongside the new one. uv keeps it around because virtual environments created with an explicit patch version still depend on it.

## Upgrade a single minor version

Pass the minor version to scope the upgrade:

```console
$ uv python upgrade 3.12
```

If 3.12 is already current:

```
Python 3.12 is already on the latest supported patch release
```

This form is useful when a release branch ships an out-of-cycle security fix and the rest of the toolchain is fine.

## Force-reinstall the latest patch

When an installation is corrupt or partially downloaded, `--reinstall` re-downloads the current patch even when uv would otherwise skip it:

```console
$ uv python upgrade --reinstall 3.12
Downloading cpython-3.12.13-aarch64-apple-darwin (download) (16.9MiB)
 Downloaded cpython-3.12.13-aarch64-apple-darwin (download)
Installed Python 3.12.13 in 850ms
 ~ cpython-3.12.13-aarch64-apple-darwin (python3.12)
```

The leading `~` indicates an in-place reinstall.

## Handle venvs pinned to an exact patch

A virtual environment created with an explicit patch version links directly at that patch directory:

```console
$ uv venv -p 3.11.8 .venv-frozen
$ readlink .venv-frozen/bin/python
/root/.local/share/uv/python/cpython-3.11.8-x86_64-unknown-linux-gnu/bin/python3.11
```

`uv python upgrade` cannot transparently move this venv to a newer patch. Either recreate the venv against the minor pin (`uv venv -p 3.11`), or accept that the venv stays on its requested patch until you delete and recreate it.

> [!NOTE]
> The same applies if you pinned a project with `uv python pin 3.11.8`. Pinning to a minor version (`uv python pin 3.11`) lets transparent upgrades reach the project's venv.

## Prune retained patch versions

Old patch directories accumulate over time. Each is roughly 100&nbsp;MB. List installed versions:

```console
$ uv python list --only-installed
```

Remove ones nothing depends on:

```console
$ uv python uninstall 3.11.8
```

If a venv still references the removed patch, recreate it before pruning. Use `uv python uninstall <minor>` (e.g. `uv python uninstall 3.11`) to remove every installed patch for a minor version at once.

## Frequently asked questions

### Does `uv python upgrade` cross minor versions?

No. Upgrading from 3.12 to 3.13 changes dependency resolution and possibly compatibility, so uv requires an explicit `uv python install 3.13` and a project pin change. See [how to change the Python version of a uv project](https://pydevtools.com/handbook/how-to/how-to-change-the-python-version-of-a-uv-project.md).

### Does it work for PyPy or GraalPy?

uv's transparent patch-upgrade mechanism is designed for CPython. PyPy and GraalPy ship at most one patch release per minor on uv's index, so there's nothing to upgrade across. To install or refresh a PyPy build, use `uv python install pypy@3.11` or `uv python install --reinstall pypy@3.11`.

### What if a patch upgrade introduces a regression?

The previous patch directory is still on disk. Recreate the affected venv against the older patch (`uv venv -p 3.11.8`) until the upstream fix lands. Pin projects to the older patch with `uv python pin 3.11.8` if needed.

## Related

- [uv: A Complete Guide](https://pydevtools.com/handbook/explanation/uv-complete-guide.md) covers what uv does, how fast it is, the core workflows, and recent releases.
- [How to install Python with uv](https://pydevtools.com/handbook/how-to/how-to-install-python-with-uv.md)
- [How to change the Python version of a uv project](https://pydevtools.com/handbook/how-to/how-to-change-the-python-version-of-a-uv-project.md)
- [How to fix Python version incompatibility errors in uv](https://pydevtools.com/handbook/how-to/how-to-fix-python-version-incompatibility-errors-in-uv.md)
- [How to upgrade uv](https://pydevtools.com/handbook/how-to/how-to-upgrade-uv.md)
- [What is a `.python-version` file?](https://pydevtools.com/handbook/explanation/what-is-a-python-version-file.md)
- [How do pyenv and uv compare for Python interpreter management?](https://pydevtools.com/handbook/explanation/how-do-pyenv-and-uv-compare-for-python-interpreter-management.md)
