Welcome back! If you haven’t checked out Part 1, now’s the time to do so. We covered how uv
simplifies managing dependencies, creating virtual environments, Python versions, and inline metadata. Now, let's go deeper into the magic of uv
and explore its advanced features that can take Python development to the next level.
1. How uv
Manages Dependencies with pyproject.toml
In Part 1, we briefly touched on adding dependencies to your Python project using uv
. Let's expand on how uv
integrates tightly with pyproject.toml
, which is the standardized format for Python project configurations.
The uv add
Command & pyproject.toml
When you use the uv add
command, uv
automatically updates your pyproject.toml
file. This file contains all your project metadata, including dependencies. Think of it as the central brain of your project. Here’s an example:
$ uv add fastapi
Your pyproject.toml
file will then reflect this change and uv
resolves dependencies automatically:
[tool.uv.dependencies]
fastapi = ">=0.68,<1.0"
This makes your dependencies explicit and your project easily shareable with others. Whenever you or someone else clones your project, simply running uv
will install the same packages listed.
Version Pinning & Constraints
One of uv
's strengths is that it makes managing exact package versions easy. You can pin specific versions directly in the pyproject.toml
file or set version ranges:
[tool.uv.dependencies]
flask = "==2.0.1"
This prevents any surprises from version mismatches and ensures stability.
Extras and Optional Dependencies
Need optional packages that not all users will require? You can easily declare these in your pyproject.toml
:
[tool.uv.dependencies]
fastapi = { version = ">=0.68,<1.0", extras = ["all"] }
Install the optional extras whenever needed:
$ uv add fastapi[all]
This modular approach keeps your project flexible and avoids unnecessary bloat.
2. Locking Dependencies with the uv.lock
File
Whenever you add or update dependencies using uv
, it doesn't just modify your pyproject.toml
file. uv
also creates a uv.lock
file. Why is this important?
-
Precise Versioning: The
uv.lock
file locks in the exact versions of all dependencies and their transitive dependencies (packages that your dependencies rely on). -
Reproducible Environments: Whether it’s you coming back to a project after a break or a colleague cloning your repo, running
uv
will install the exact versions specified in theuv.lock
file.
The result? A consistent, reliable environment that eliminates the "it works on my machine" problem.
3. Managing Tools: Global vs. Project-Specific
In Part 1, we discussed how uv
makes it easy to install CLI tools. Now, let's break down how uv
distinguishes between global and project-specific tools.
Installing Global Tools
Installing a tool globally with uv
is simple:
$ 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 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 Tools Ephemerally with uvx
For quick, one-off tool usage without permanently installing it, uvx
is your friend:
$ uvx black my_script.py
This runs black
within a temporary virtual environment and then cleans up afterward. It's like pipx
, but faster and tightly integrated with uv
.
4. Creating & Using Virtual Environments the Right Way
Making Virtual Environments Easy
In Part 1, we explained how uv
defaults to using virtual environments for all package installations. Here's a quick recap:
$ uv venv
This command creates a .venv
directory in your project. If you want to use a custom directory or Python version:
$ uv venv my_venv --python 3.11
You can then activate your virtual environment as you normally would:
$ source .venv/bin/activate
Automatic Environment Detection
Whenever you work on a project managed by uv
, the tool will automatically detect and use the appropriate virtual environment without any additional setup. No need to worry about manually activating or deactivating environments.
5. uv
and Existing Environments
Already using another environment manager like conda
? No problem. uv
is built to play nicely with external virtual environments.
Automatic Environment Detection & Integration
When you use uv pip install
or uv add
, uv
searches for existing virtual environments:
-
Activated environments (e.g.,
VIRTUAL_ENV
orCONDA_PREFIX
). - A
.venv
directory in your current project.
If uv
doesn’t find a virtual environment, it will prompt you to create one to keep your environment clean and isolated.
6. uv
vs. conda
: When to Use What?
uv
handles almost all your Python package and environment needs quickly and efficiently. However, if your project has non-Python dependencies (like system-level packages) or requires multi-language support (e.g., Python and R), conda
might still be a better choice.
For pure Python workflows, uv
is often a faster and more flexible alternative, simplifying the management of virtual environments and dependencies.
uv
provides an all-in-one solution for managing Python dependencies, environments, and tools. By combining speed, reproducibility, and simplicity, it aims to make your Python workflow more efficient than ever.
So whether you're starting a new project, working with multiple Python versions, or managing complex dependencies—uv
has you covered.
Although there is still a gap to fill, the conda
integration. Pixi
+ uv
could be the awaited python manager to rule them all.
Try it today, and see how it transforms your Python development process. 🚀
If you haven’t read Part 1, check it out here to get an overview of how uv
can supercharge your Python projects. Happy coding! 🐍✨
For full details and documentation, check out the official uv
docs.
Top comments (0)