Python
UV is a modern, high-performance Python package manager and installer written in Rust.
Key features that make UV stand out:
Lightning-fast package installation and dependency resolution
Compatible with existing Python tools and workflows
Built-in virtual environment management
Support for modern packaging standards
Reliable dependency locking and reproducible environments
Memory-efficient operation, especially for large projects
Install
[!NOTE]brew also install
zsh completions
when you run below command
brew install uv
Add UV_TOOL_BIN_DIR
to paths
[!NOTE] We automatically add it to path, if you use our dotfiles, See extra.zsh
export PATH="$HOME/.local/bin:$PATH"
Usage
Initializing a new project
[!NOTE] For lib projects use:
uv init --lib
uv init explore-uv
cd explore-uv
uv sync # create lockfiles, install Python deps
Git is automatically initialized and main git-related files like .gitignore
and an empty README.md
are generated.
Dependency Management With UV
Adding initial dependencies to the project
UV combines the environment creation and dependency installation into a single command. UV also updates the pyproject.toml
and uv.lock
files after each add command.
# Installing the latest version of a package:
uv add pydantic
# Installing a specific version:
uv add requests=2.1.2
# Change the bounds of a package's constraints:
uv add 'requests<3.0.0'
# Make a dependency platform-specific:
uv add 'requests; sys_platform="linux"'
The first time you run the add command, UV creates a new virtual environment in the current working directory and installs the specified dependencies. On subsequent runs, UV will reuse the existing virtual environment and only install or update the newly requested packages, ensuring efficient dependency management.
[!TIP] You can also just edit these dependencies manually (this is what I usually do), and just run
uv sync
whenever you do, to update youruv.lock
(you shouldnβt edit these manually) and yourvenv
.
To remove a dependency from the environment and the pyproject.toml
file, you can use the uv remove
command. It will uninstall the package and all its child-dependencies:
uv remove pydantic
Adding optional dependencies
Optional dependencies are packages that are not required for the core functionality of your project but may be needed for specific features. For example, Pandas has an excel
extra and a plot
extra to avoid the installation of Excel parsers and matplotlib unless someone explicitly requires them.
With UV, this syntax is slightly different. First, ensure that the core Pandas package is installed:
uv add pandas
Then, add its optional dependencies:
uv add pandas --optional plot excel
Dependency groups
Dependency groups allow you to organize your dependencies into logical groups, such as development dependencies, test dependencies, or documentation dependencies. This is useful for keeping your production dependencies separate from your development dependencies.
To add a dependency to a specific group, use the --group
flag:
uv add --group group_name package_name
Managing Tools: Global vs. Project-Specific
uv makes it easy to install CLI tools
Installing Global Tools
uv tool install black
This makes black available across all your projects but keeps it in its isolated virtual environment, avoiding system-wide conflicts.
Project-Specific Tools
If you need a tool for a specific project, add it directly as a dependency:
uv add --group dev ruff
This keeps the tool local to your project and listed in your pyproject.toml
.
Your other projects remain unaffected, allowing for isolated development environments.
Running Python scripts with UV
Once you install the necessary dependencies, you can start working on your Python scripts as usual. UV provides a few different ways to run Python code:
uv run hello.py
The run command ensures that the script is executed inside the virtual environment UV created for the project.
Environment variables
uv run
can load environment variables from dotenv files (e.g., .env
, .env.local
, .env.development
), powered by the dotenvy crate.
To load a .env
file from a dedicated location, set the UV_ENV_FILE
environment variable, or pass the --env-file
flag to uv run
.
The --env-file
flag can be provided multiple times, with subsequent files overriding values defined in previous files.
Changing Python versions for the current project
You can switch Python versions for your current UV project at any point as long as the new version satisfies the specifications in your pyproject.toml file.
For example, the following file requires Python versions 3.9 and above:
requires-python = ">=3.9"
What Are UV Tools And How to Use Them?
Some Python packages are exposed as command-line tools like ruff
or black
for code formatting and linting, pytest
for testing, ty
for type checking, etc. UV provides two special interfaces to manage these packages:
UV provides two special interfaces to manage these packages:
Using
uv tool run
:uv tool run black hello.py
Running Tools Ephemerally with
uvx
command:uvx black hello.py
Read the UV Tools section of the documentation to learn more about these interfaces.
Linting
Letβs also add Ruff:
uv add --dev ruff
uv run ruff format # format (what black used to do)
uv run ruff check --fix # lint (what flake8 used to do)
Typing
first install ty
uv add --dev ty
configure it
Example configuration:
[tool.ty]
respect-ignore-files = true
[tool.ty.rules]
unused-ignore-comment = "warn"
redundant-cast = "ignore"
possibly-unbound-attribute = "error"
possibly-unbound-import = "error"
And now you can run it with uv run ty check example.py
. And, as with the type checker, you should get it integrated with your editor.
Testing
Refer for full testing docs
uv add --dev pytest
Sample test
# tests/test_nothing.py
from explore-uv.hello import main
def test_hello():
main("what?") # main doesn't accept any args π
And then:
uv run pytest
...
FAILED tests/test_import.py::test_hello -
TypeError: main() takes 0 positional arguments but 1 was given
Iβll leave fixing the test as an exercise for the reader.
Task runner
Letβs install it with uv add --dev poethepoet
and set it up right at the top of the pyproject.toml
[tool.poe.tasks]
# run with eg `uv run poe fmt`
fmt = "ruff format"
lint = "ruff check --fix"
check = "pyright"
test = "pytest"
# run all the above
all = [ {ref="fmt"}, {ref="lint"}, {ref="check"}, {ref="test"} ]
Then any time youβve made some changes or are preparing to commit, you can run uv run poe test
or just run uv run poe all
and the full suite of tools will get to work for you!
You can always still run uv run ruff format
or whatever
Switching From PIP and Virtualenv to UV
Converting an existing
virtualenv
projectstart by generating a requirements.txt file from your current environment if you haven't already:
pip freeze > requirements.txt
Then, create a new UV project in the same directory:
uv init .
Finally, install the dependencies from your requirements file:
uv pip install -r requirements.txt
Replacing common pip/virtualenv commands
pip/virtualenv commandUV equivalentpython -m venv .venv
uv venv
pip install package
uv add package
pip install -r requirements.txt
uv pip install -r requirements.txt
pip uninstall package
uv remove package
pip freeze
uv pip freeze
pip list
uv pip list
Monorepo
This is the bonus section! If youβre building something in a big team, and you donβt have a monolith, youβre likely to have multiple apps and libraries intermingling.
The best place to start is to have a glance at the uv Workspace docs. Then I recommend checking out the example python monorepos: uv-monorepo, postmodern-mono
Structure
There are three packages split into libs and apps:
libs: importable packages, never run independently, do not have entry points
apps: have entry points, never imported
Note that neither of these definitions are enforced by anything in
Python
oruv
.
.
βββ pyproject.toml # root pyproject
βββ uv.lock
βββ libs
βΒ Β βββ greeter
βΒ Β βββ pyproject.toml # package dependencies here
βΒ Β βββ agentic # all packages are namespaced
βΒ Β Β Β βββ greeter
βΒ Β Β Β βββ __init__.py
βββ apps
Β Β βββ server
Β Β β βββ pyproject.toml # this one depends on libs/greeter
Β Β β βββ Dockerfile # and it gets a Dockerfile
Β Β β βββ agentic
Β Β β Β Β βββ server
Β Β β Β Β βββ __init__.py
Β Β βββ mycli
Β Β Β Β βββ pyproject.toml # this one has a cli entrypoint
Β Β Β Β βββ agentic
Β Β Β Β Β Β βββ mycli
Β Β Β Β Β Β βββ __init__.py
In a workspace, each package defines its own pyproject.toml
, but the workspace shares a single lockfile, ensuring that the workspace operates with a consistent set of dependencies.
Getting started
To create a workspace, add a tool.uv.workspace
table to a pyproject.toml
, which will implicitly create a workspace rooted at that package.
[!TIP] By default, running
uv init
inside an existing package will add the newly created member to the workspace, creating atool.uv.workspace
table in the workspace root if it doesn't already exist.
Setup apps/libs projects in monorepo
cd apps
uv init --app server --description 'agents server'
uv init --app cli --description 'cli app'
cd ../libs
uv init --lib utils --description 'Utility functions'
run from root when using --package
option
# run format with ruff
uv run --package server ruff format
# or format via poe
uv run --package server poe fmt
# add dependency to individual package
uv add --package cli typer
# run individual package script
uv run --package cli ai_agents_cli
Dependencies between workspace members are editable.
Commands
Managing Python Versions in UV
uv python install # Install Python versions.
uv python list # View available Python versions.
uv python list --only-installed # Listing existing Python versions
uv python find # Find an installed Python version.
uv python pin # Pin the current project to use a specific Python version.
uv python uninstall # Uninstall a Python version.
To learn more about managing Python versions with UV, refer to the documentation.
Miscellaneous
# To generate a requirements.txt from a UV lock file, use the following command:
uv export -o requirements.txt
Utility
# self update
uv self update
# clear cache
uv cache clean
# Remove outdated cache entries
uv cache prune
References
How to Learn Python From Scratch in 2025: An Expert Guide
UV features
Beyond Hypermodern: Python is easy now
Mastering Python Project Management with uv: Part 2 β Deep Dives and Advanced Use
Last updated
Was this helpful?