Stop Setting Up Python Projects the Old Way. Use uv for Speed and Cleaner Environments
A hands-on guide to using uv to install Python, create projects, manage dependencies, run commands, and replace slower venv-plus-pip habits in modern Python workflows.
The old Python setup tax: create venv, activate it, upgrade pip, install deps, sync tooling manually, hope the right interpreter is active in CI.
uvexists because too many Python workflows still waste time on setup friction instead of actual work.
Why uv is getting so much attention
Astral’s uv is attractive for a simple reason: it collapses a pile of scattered Python workflow steps into one fast tool. Instead of treating Python installation, virtual environments, dependency sync, command execution, and packaging like separate chores, uv pulls them into one workflow.
If you are still doing this on every project:
python3 -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -r requirements.txtyou are not “wrong,” but you are doing more repetitive setup than you need to.
Install uv
On macOS and Linux, the official install method is:
curl -LsSf https://astral.sh/uv/install.sh | shOn macOS with Homebrew:
brew install uvVerify it:
uv --versionStart a fresh project
Create a project:
uv init myapp
cd myappThat gives you a clean starting structure without the usual ceremony.
Add dependencies
Instead of manually editing requirements and hoping you remember what changed:
uv add fastapi
uv add uvicorn --devThis updates the project dependency metadata directly. For teams, that matters because dependency management becomes explicit instead of half-manual.
Run code without activation drama
One of the nicest parts of uv is that you do not need to keep obsessing over whether the shell session is “inside” the environment.
Run a Python file:
uv run python main.pyRun a framework command:
uv run fastapi dev main.pyRun tests:
uv run pytestThat sounds small until you notice how many path mistakes disappear when teams stop juggling activation state across terminals.
Install Python versions with uv
This is where uv starts to feel like a real workflow upgrade rather than just another wrapper.
Install a Python version:
uv python install 3.12List managed versions:
uv python listThat means fewer “works on my machine” moments caused by people silently using different interpreters.
Sync environments cleanly
If the project already has declared dependencies and you want the environment to match:
uv syncThis is the kind of command that helps a lot in CI and on teams because it makes “install what the project says it needs” a direct operation instead of a custom shell ritual.
A realistic FastAPI example
Create a simple app:
from fastapi import FastAPI
app = FastAPI()
@app.get("/health")
def health():
return {"ok": True}Then run it:
uv add fastapi
uv add uvicorn --dev
uv run uvicorn main:app --reloadThat is already cleaner than the usual venv activation dance plus ad hoc package installs.
When uv is especially worth it
It shines when you want:
- faster dependency operations
- cleaner onboarding for new developers
- fewer interpreter mismatches
- one command shape across local and CI usage
What it replaces
It does not magically erase every Python packaging decision, but it absolutely weakens the old habit of gluing together:
- manual venv creation
- direct
pip installdrift - undocumented interpreter assumptions
- shell-state-dependent command runs
The practical recommendation
If you are starting a new Python service or CLI in 2026, it is hard to justify ignoring uv. Even if you do not move your entire org immediately, it is a very strong default for new codebases because it reduces boring setup work without making the workflow obscure.
Good tooling is not the point of the project. But bad setup is one of the fastest ways to make a healthy project feel annoying from day one.