Skip to main content
  1. Blog/
  2. Programming & Dev/

How to use UV when you are used to PIP

·981 words·5 mins

This post teach you how to use uv and my recommendations when migrating from pip.

How UV works #

UV manages the python environment and version by itself. You dont need to install any python version, it will install the version declared at .python-version if needed or use your $PATH python.

UV will enter or create a .venv whenever you run uv run as needed and will manage it for you.

UV will create a new one-time-use venv whenever you run uvx.

That way our project dependency stay clean and we avoid dependency conflicts.

Setup development with UV #

If you already have python in your OS or prefers to manage python versions with another tool (like mise or asdf), UV will always try to use what you have in your $PATH before trying to install a new version in your OS.

Installing UV Standalone #

The standalone uv installation is easier to upgrade if you’re not tech savvy, if you prefer to install via another package manager check the docs.

Windows #

On PowerShell run

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.9.29/install.ps1 | iex"

If you see the error The term 'uv' is not recognized as the name of a cmdlet reboot your OS.

Then check if it worked with

uv self version

*nix (Mac/Linux) #

With curl installed run

curl -LsSf https://astral.sh/uv/0.9.29/install.sh | sh;

then check if it worked with

uv self version

Upgrading UV Standalone #

If you run uv self update and get a newer version make sure to also bump uv versions on everywhere that mentions it in your project (Dockerfile, ci, Docs)

Windows #

uv self update

*nix #

It’s recommended to add UV_NO_MODIFY_PATH to avoid changing the $PATH and breaking something

UV_NO_MODIFY_PATH=1 uv self update

Shell Autocompletion #

Fish/Elvish/Others #

Check the Shell Autocompletion on uv docs.

PowerShell #

UV #
if (!(Test-Path -Path $PROFILE)) {
  New-Item -ItemType File -Path $PROFILE -Force
}
Add-Content -Path $PROFILE -Value '(& uv generate-shell-completion powershell) | Out-String | Invoke-Expression'
UVX #
if (!(Test-Path -Path $PROFILE)) {
  New-Item -ItemType File -Path $PROFILE -Force
}
Add-Content -Path $PROFILE -Value '(& uvx --generate-shell-completion powershell) | Out-String | Invoke-Expression'
Zsh #
echo 'eval "$(uv generate-shell-completion zsh)"' >> ~/.zshrc
echo 'eval "$(uvx --generate-shell-completion zsh)"' >> ~/.zshrc

then source the config

source ~/.zshrc
Bash #
echo 'eval "$(uv generate-shell-completion bash)"' >> ~/.bashrc
echo 'eval "$(uvx --generate-shell-completion bash)"' >> ~/.bashrc

then source the config

source ~/.bashrc

Using UV #

When you run uv run or uv tree it automatically updates the lock and syncs.

If you do not have a venv yet the uv sync or uv run will create it for you.

If you do not have python yet uv will download it for you.

To update the project environment (venv) run

uv sync

To update the project lock file run

uv lock

To list the dependency tree

uv tree

To add a package with specific version

uv add "package~=1.2.3"

To add a dev only package with specific version

uv add --dev "package~=1.2.3"

To remove a package

uv remove package

Any package installed in the pyproject.toml that used to run with python should use uv

uv run <command>

for example to run pytest

uv run pytest

Any packages that are not in the pyproject.toml should use uvx

uvx <command>
uvx ruff format

for tools like ruff, it’s good to pin the latest version

uvx ruff@latest format

Inside Docker uv is also used

docker compose exec web uv run manage.py migrate

Using extra environment variables in docker #

To test something pytest is needed which is an environment only dependency so the environment variable UV_NO_DEV=0 is needed as an e flag when entering the container to tell uv to use the dev dependencies (pytest). If you want to pass more variables like which DB to use for test in an example where you have different DB engines you can just add more env variables to docker through the e flag.

docker compose exec -e TEST_DB_ENGINE=sqlite -e UV_NO_DEV=0 web uv run pytest

Pip Migration #

If you used the old requirements.txt and want to use uv it is recommended to switch to the modern pyproject.toml as per the PEP 621. By default when you run uv add <package> it will add it on a pyproject.toml as dependencies. For developer only dependencies do uv add --dev <package>.

Since simple requirements.txt do not have dependency groups to differentiate between dev and prod dependencies I recommend going through your requirements.txt and assigning correctly which is what.

I always like to pin dependencies versions with ~= that is the PEP 440 identifier for compatible releases and pin dev dependencies with >= to use the latest.

This is an example of a project with your-dependencies and pytest installed in their correct places.

[project]
name = "project-name"
version = "0.0.1"
description = "cool project"
readme = "README.md"
requires-python = "~=3.14.2"
dependencies = [
    "your-dependencies~=0.0.0",
]

[dependency-groups]
dev = [
    "pytest>=9.0.2",
]

Builtin ruff format support #

uv format is a builtin alias to ruff format that is slightly faster because it doesn’t create a venv

uv format

same as

uvx ruff format

You can pass ruff format arguments to ruff by doing

uv format -- --line-length 80

same as

uvx ruff format --line-length 80

UV also have builtin support for the --check and --diff flags of ruff format.

ruff format is a drop-in replacement for Black, uv format --check is the equivalent of black --check.

ruff check is a drop-in replacement for Flake8, isort, pydocstyle, pyupgrade, autoflake, and more.

Both commands are from ruff but behave completely different because ruff format --check is running a code formatter without applying the format while ruff check is running the linters as you configured in ruff.

uv format --check

same as

uv format -- --check

same as

uvx ruff format --check

The other uv format flags do not behave the same as ruff format flags and are used to either configure uv itself or configure how ruff format needs to behave in relation to uv.