How to upgrade all Python packages with pip

pip is the package installer for Python. It has no upgrade-all command, so everybody copies a shell one-liner from somewhere. This article shows the better version, and demonstrates the failure the one-liners can leave behind.

There is no built-in command

pip install --upgrade takes package names, and there is no way to say “all of them”. That omission is deliberate — upgrading everything at once is rarely what a working project wants — but the need still comes up, especially in a scratch environment.

Start by looking

$ pip list --outdated
Package            Version   Latest    Type
certifi            2022.9.24 2026.7.22 wheel
charset-normalizer 2.1.1     3.5.1     wheel
idna               3.3       3.19      wheel
requests           2.28.1    2.34.2    wheel
urllib3            1.26.12   2.7.0     wheel

That is worth doing on its own before you change anything.

The one-liner everybody copies

$ pip freeze | cut -d= -f1 | xargs pip install -U

It works often enough to keep being shared, and it has two problems.

The first is pip freeze. Its job is to produce a reproducible requirements file, so it emits more than plain names — editable installs as -e ..., VCS checkouts as full git+https://... URLs, and local packages as file paths. cut -d= -f1 turns each of those into something that is not a package name, and pip install -U then either fails or installs the wrong thing.

Use the machine-readable output instead:

$ pip list --outdated --format=json
[{"name": "certifi", "version": "2022.9.24", "latest_version": "2026.7.22", ...

which gives you exactly the names, and only the ones that need upgrading:

$ pip list --outdated --format=json \
    | python -c "import json,sys; print(' '.join(p['name'] for p in json.load(sys.stdin)))"
certifi charset-normalizer idna requests urllib3

Feed that to a single pip install --upgrade and you are done:

$ pip install --upgrade certifi charset-normalizer idna requests urllib3

Note the single command. That matters, and it is the second problem.

Upgrading one at a time can break the set

Most of the one-liners run pip install -U once per package. pip resolves dependencies per install command, so a loop of n commands is not the same as one command with n packages.

Here is that going wrong. Start from a consistent environment where requests 2.28.1 requires urllib3 < 1.27:

installing requests 2.28.1 again, which needs urllib3 < 2:
No broken requirements found.

Now upgrade only urllib3, exactly as a per-package loop would:

requests 2.28.1 requires urllib3<1.27,>=1.21.1, but you have urllib3 2.7.0 which is incompatible.

pip warns during the install, and the environment is now broken. If that warning scrolled past in a hundred lines of output, nothing else tells you — until something raises at runtime.

The command that finds it afterwards is one people rarely know:

$ pip check
requests 2.28.1 has requirement urllib3<1.27,>=1.21.1, but you have urllib3 2.7.0.

Run pip check after any bulk upgrade. It is instant and it either says No broken requirements found or names the problem precisely.

What I would actually do

For a real project, do not upgrade everything. Pin your dependencies, upgrade deliberately, and let a tool that resolves the whole set at once do the work — pip-tools, Poetry or uv all do this, and all of them produce a lock file so the result is reproducible.

Two smaller things that help regardless:

Work in a virtual environment. Upgrading everything in a system Python can break tools that came from your distribution’s package manager. venv is in the standard library.

Look before you leap. pip install --dry-run --upgrade ... shows you what would change without changing it, which is worth the extra ten seconds when the list is long.

For a scratch environment

If it really is a throwaway environment and you just want everything current:

$ pip list --outdated --format=json \
    | python -c "import json,sys; print(' '.join(p['name'] for p in json.load(sys.stdin)))" \
    | xargs -r pip install --upgrade
$ pip check

One resolution, no freeze parsing, and a check at the end. The -r on xargs stops it running pip install --upgrade with no arguments when nothing is outdated.

About Netcup (advertisement)

The German host Netcup offers, among other things, affordable and powerful web hosting packages, KVM-based root servers and dedicated servers. With our voucher codes you can save even more (6€ off your first order, 30% off all KVM-based root servers, ...).