If you are a developer, I am sure you heard the term “dependency hell”. As a data scientist at a consulting firm, I always work in different environments and stacks every time I move from a project to project. And of course, I always go through this dependency hellI wasting an entire day chasing down a dependency issue in a project. It’s a nightmare that you want to avoid but ended up happening every single project. If you are like me, you should use uv
, and here are 5 things you should do when using uv
.
But before jumping right in to it, let me briefly explain what uv
is.
What is UV?
It’s a package manager in Python, like pip. But uv
is a faster and more efficient alternative to pip. Unlike pip, which resolves dependencies sequentially and installs packages individually, uv
uses its own dependency resolution algorithm that constructs a complete dependency graph before installation, reducing conflicts and ensuring compatibility. Also, it runs in parallel, allowing multiple packages to be downloaded and installed simultaneously. Lastly, its caching mechanism is phenomenal, making uv
the best modern package manager in Python.
Now you know what uv
is, let’s get into the 5 best practices:
1. Create and Manage Virtual Environments
Isolating your project’s dependencies in a virtual environment prevents conflicts between packages and ensures that your development setup remains consistent and reproducible. By creating a separate virtual environment for each project, you avoid the risk of one project’s dependencies interfering with another’s, which can lead to unexpected behavior and difficult-to-trace bugs.
To create and activate a new virtual environment using uv
:
uv create-env myenv
uv activate myenv
If you prefer to use conda
for managing environments but want to leverage uv
for package management:
conda create -n myenv python=3.10
conda activate myenv
uv install flask
You can also use pip
within UV-managed environments:
uv create-env myenv
uv activate myenv
pip install flask
Whether you use uv
, conda
, or pip
for environment creation, integrating uv
into the process will help you maintain a stable development setup.
2. Lock Your Dependencies with uv
Locking dependencies ensures that your project uses the exact same package versions across all environments, making your work reproducible and stable. It’s very important when you work on a project where you need to deploy your code in different dev environments.
After installing your initial set of dependencies, generate a lockfile:
uv install requests numpy pandas
uv lock
If you’re using pip
within a uv
-managed environment, you can still benefit from uv
locking mechanism:
uv create-env myenv
uv activate myenv
pip install requests numpy pandas
uv lock
By locking your dependencies, you guarantee that your project will behave consistently regardless of where it’s deployed or who’s working on it. Trust me, this will save you from having “dependency hell”.
3. Audit Your Dependencies Regularly
Regularly auditing your dependencies helps identify and mitigate security vulnerabilities in your project. There are many security and monitoring tools, which will capture security vulnerabilities in your dependencies. But uv
also provides one. As a developer, you are responsible for discovering vulnerabilities in your code, so make sure to audit dependencies to avoid any security risks.
To audit your dependencies with uv
:
uv audit
4. Optimize Package Installation with UV’s Parallel Processing
This is the core benefit of using uv
: it does parallel processing. Its parallel processing capability allows you to install packages more quickly by handling multiple installations simultaneously. This saves time and improves your workflow efficiency, allowing you to focus more on coding and eating snacks.
Try install multiple packages simultaneously:
uv install flask django celery
If you’re using pip
for some packages, you can still take advantage of uv
’s efficiency:
uv create-env myenv
uv activate myenv
uv install requests
pip install flask django celery
5. Keep Your Dependencies Updated with Care
This goes back to the point I made with security risks. Keeping your dependencies up to date will save you from security risks and bring you new features, performance improvements, and security patches. However, updating without caution can introduce new conflicts or break your existing code. By carefully managing updates, you can ensure your project remains functional while benefiting from the latest advancements.
To update a specific package(e.g. requests
) while respecting the lockfile:
uv update requests
Or if you want to update all dependencies:
uv update --all
If you prefer using pip
for updates:
uv activate myenv
pip install --upgrade requests
uv lock
Wrapping Up
Truly, uv
saved me a lot, and it can help you, too. By following these best practices, you can make the most of the uv
package manager and maintain efficient, secure, and reliable Python projects. Whether you prefer using uv
alone or combined with tools like conda
and pip
, make sure to use uv
to save you from “dependency hell”.