What is uv and Why Should Python Developers Use It?
Problem
I was starting a new Python project. I ran the usual commands:
python -m venv .venvsource .venv/bin/activatepip install requests pandas numpypython main.pyThen I opened a new terminal tab to run a quick test. My script failed because I forgot to activate the virtual environment. Again.
$ python main.pyTraceback (most recent call last): File "main.py", line 1, in <module> import requestsModuleNotFoundError: No module named 'requests'I spent the next 20 minutes debugging why my packages weren’t installed. Turns out I had installed them globally in one terminal while my virtual environment was active in another. Classic Python environment mess.
This happens every single project. I waste 15-30 minutes per project just on environment setup and debugging. Multiply that by dozens of projects per year, and I’m losing hours to something that should just work.
What’s Happening?
Python’s virtual environment system is fundamentally broken for developer workflow:
1. Create venv manually: python -m venv .venv2. Activate in EVERY terminal: source .venv/bin/activate3. Remember to activate before installing: Forgot? Now packages are global4. Manage multiple venvs across projects: Where was that venv again?5. Slow package installation: pip resolves dependencies for minutes6. Inconsistent environments: "Works on my machine" syndromeA Reddit thread confirmed I’m not alone. The top comment with 15 upvotes was blunt: “Don’t waste time managing virtual environments. Learn how to use uv. It takes care of everything for you.”
Multiple other developers simply responded: “Use UV.”
The community consensus was clear. There’s a tool that eliminates this entire problem.
The Solution: uv
uv is a modern Python package installer and resolver from Astral. It’s written in Rust and automatically manages virtual environments without any manual activation.
Let me try the basic workflow:
# Initialize a new projectuv init my-project
# Navigate into projectcd my-project
# Add dependencies - no activation neededuv add requests pandas numpy
# Run my script - uv handles everythinguv run python main.pyThat’s it. Three commands. No manual venv creation. No activation. No forgetting to activate.
Comparison: Traditional vs uv
Let me see the difference clearly:
# Traditional approach (pip + virtualenv) - Multiple error-prone stepspython -m venv .venvsource .venv/bin/activate # Windows: .venv\Scripts\activatepip install requests pandas numpypython main.py# Don't forget to activate in every new terminal session!# If you forget, packages install globally# If you have multiple terminals, which one is active?
# uv approach - Three simple commandsuv init my-project && cd my-projectuv add requests pandas numpyuv run python main.py# Done. No activation. No manual venv management.Why uv Works Better
I dug into why uv eliminates the friction:
1. Automatic Virtual Environment Management
# uv creates and manages .venv automatically$ uv add requestsResolved 6 packages in 12msInstalled 6 packages in 45ms + certifi==2024.2.2 + charset-normalizer==3.3.2 + idna==3.6 + requests==2.31.0 + urllib3==2.2.1When I run uv add, it automatically creates a virtual environment if one doesn’t exist. No manual python -m venv needed.
2. No Activation Required
# Open a new terminal? Just run your script$ uv run python main.py# uv automatically uses the correct virtual environmentThe uv run command handles environment activation internally. I never need to remember source .venv/bin/activate.
3. Blazing Fast Package Installation
# Traditional pip: Resolves and installs over 30 seconds$ pip install pandasCollecting pandas# ... waiting ...Successfully installed pandas-2.2.0
# uv: Same packages in under 1 second$ uv add pandasResolved 8 packages in 89msInstalled 8 packages in 312msuv is written in Rust. It’s 10-100x faster than pip for dependency resolution and installation.
4. Deterministic Lock Files
# uv automatically creates uv.lock$ uv add requests# Generates uv.lock with exact versionsThe uv.lock file ensures everyone on my team has identical environments. No more “works on my machine” problems.
How It Works
Let me trace through what happens:
┌─────────────────────────────────────────────────────────────┐│ uv add requests │├─────────────────────────────────────────────────────────────┤│ 1. Check if .venv exists ││ └─ If not, create it automatically ││ ││ 2. Resolve dependencies with SAT solver (Rust-based) ││ └─ Much faster than pip's backtracking ││ ││ 3. Download and install packages ││ └─ Parallel downloads, efficient caching ││ ││ 4. Update uv.lock file ││ └─ Exact versions for reproducibility │└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐│ uv run python main.py │├─────────────────────────────────────────────────────────────┤│ 1. Locate or create virtual environment ││ ││ 2. Activate environment internally ││ ││ 3. Execute command with correct Python and packages ││ ││ 4. Done - no deactivation needed │└─────────────────────────────────────────────────────────────┘The key insight: uv treats virtual environment management as an implementation detail, not a user responsibility.
Working with Development Dependencies
uv also handles dev dependencies cleanly:
# Add testing and linting tools as dev dependenciesuv add --dev pytest black ruff
# Run tests - uv handles environment automaticallyuv run pytest
# Format codeuv run black .
# Lint codeuv run ruff check .Dev dependencies are tracked separately in pyproject.toml:
[project]name = "my-project"version = "0.1.0"dependencies = [ "requests>=2.31.0", "pandas>=2.2.0",]
[project.optional-dependencies]dev = [ "pytest>=8.0.0", "black>=24.0.0", "ruff>=0.2.0",]Running Scripts with Inline Dependencies
uv supports PEP 723 inline script metadata:
# /// script# requires-python = ">=3.11"# dependencies = ["requests", "pandas"]# ///
import requestsimport pandas as pd
def fetch_data(): response = requests.get("https://api.example.com/data") return pd.DataFrame(response.json())
if __name__ == "__main__": df = fetch_data() print(df.head())# Run directly - uv handles everything$ uv run main.py# No venv setup, no pip install, just worksMigrating from pip to uv
For existing projects:
# Option 1: Install from requirements.txtuv pip install -r requirements.txt
# Option 2: Let uv manage everythinguv add $(cat requirements.txt)
# Option 3: Initialize in existing projectcd existing-projectuv inituv add $(pip freeze | cut -d= -f1)Common Mistakes When Transitioning to uv
I made these mistakes when I first started:
Mistake 1: Trying to Manually Activate Virtual Environments
# WRONG - Not needed with uv$ source .venv/bin/activate$ pip install requestsThis defeats the purpose of uv. The correct approach:
# CORRECT - Let uv handle everything$ uv add requests$ uv run python main.pyMistake 2: Mixing uv with pip
# WRONG - Using pip in a uv project$ uv add requests$ pip install pandas # This bypasses uv's tracking!uv can install from PyPI just like pip. Use uv exclusively:
# CORRECT - Use uv for all packages$ uv add requests pandasMistake 3: Not Committing Lock Files
# WRONG - Ignoring uv.lock$ git add .$ git commit -m "Add dependencies"# .gitignore: uv.lock <-- Don't do this!Lock files ensure reproducibility. Always commit them:
# CORRECT - Commit uv.lock for reproducible builds$ git add pyproject.toml uv.lock$ git commit -m "Add dependencies with lock file"Mistake 4: Assuming uv is Only for New Projects
uv works great in existing projects:
# Migrate existing projectcd my-existing-projectuv init # Creates pyproject.tomluv add $(pip freeze | cut -d= -f1) # Add all current packagesMistake 5: Ignoring Performance Benefits
I used to think “pip is fast enough.” Then I timed it:
# pip timing$ time pip install pandas numpy scipy matplotlib# real: 47 seconds
# uv timing$ time uv add pandas numpy scipy matplotlib# real: 2.1 secondsIn CI/CD pipelines, this 45-second saving per build adds up to hours saved per month.
Why This Matters
After using uv for a month, I’ve noticed real improvements:
Traditional workflow: 15-30 minutes environment setupuv workflow: 1-2 minutes
Projects per month: ~10Time saved per month: ~4 hoursMore importantly, I’ve eliminated entire categories of errors:
1. Installing packages globally instead of in venv2. Forgetting to activate venv before pip install3. Different package versions between dev and prod4. "Works on my machine" debugging sessions5. CI/CD failures due to environment mismatchesThe mental overhead of virtual environment management is completely gone. I think about code, not environment setup.
The Reason uv Exists
Astral (the company behind uv) recognized that Python’s tooling friction was driving developers away. The virtual environment system made sense in 2004. In 2024, it’s unnecessary cognitive overhead.
uv’s design philosophy:
1. Virtual environments are implementation details, not user concerns2. Dependency resolution should be fast and deterministic3. One tool should handle everything (install, run, manage)4. Developers should focus on code, not toolingThis aligns with how modern language tools work. Rust has cargo. Node has npm. Go has go mod. Python finally has uv.
Summary
uv eliminates Python virtual environment complexity through automatic management, 10-100x faster performance than pip, and a simple three-command workflow:
uv init my-project && cd my-project # Create projectuv add requests pandas numpy # Add dependenciesuv run python main.py # Run codeThe key insight is that virtual environment management should be invisible. When I install a package, I want it available. When I run a script, I want it to work. I shouldn’t need to remember activation commands or debug environment issues.
After a month of using uv, I’ve reclaimed hours previously lost to environment debugging. More importantly, my development workflow is simpler. I think about code, not tooling.
Install uv with:
curl -LsSf https://astral.sh/uv/install.sh | shThen try uv init in your next project. The first time you run uv run python script.py without ever typing source .venv/bin/activate, you’ll understand why developers are switching.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 uv Official Documentation
- 👨💻 Astral - uv GitHub Repository
- 👨💻 Reddit: Python Virtual Environment Discussion
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments