DEV Community

Cover image for Mastering Python Project Management with uv: Part 2 – Deep Dives and Advanced Use
Thomas Bury
Thomas Bury

Posted on

Mastering Python Project Management with uv: Part 2 – Deep Dives and Advanced Use

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
Enter fullscreen mode Exit fullscreen mode

Your pyproject.toml file will then reflect this change and uv resolves dependencies automatically:

[tool.uv.dependencies]
fastapi = ">=0.68,<1.0"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"] }
Enter fullscreen mode Exit fullscreen mode

Install the optional extras whenever needed:

$ uv add fastapi[all]
Enter fullscreen mode Exit fullscreen mode

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 the uv.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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

  1. Activated environments (e.g., VIRTUAL_ENV or CONDA_PREFIX).
  2. 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)