If you have worked in Python long enough, you probably know the old ritual by heart. Create a virtual environment. Activate it. Install packages with pip. Freeze dependencies. Repeat the same dance in CI, in Docker, and on every new laptop.
That workflow still works. It is also why so many teams end up with shell snippets in their README, drift between requirements.in and requirements.txt, and a steady stream of “it works on my machine” messages.
uv is getting attention because it cuts through that sprawl. Astral built it as a Python package and project manager that handles project setup, dependency resolution, lockfiles, Python version pinning, script execution, and a pip-compatible migration layer. The speed claims get the headlines. The bigger win is simpler day-to-day project management.
This guide explains how uv works, how it compares with pip + venv and Poetry, how to migrate an existing project, and where you should still keep the older tools. If you are starting a new Python app in 2026, this is one of the first choices worth making.
What you’ll learn:
- How a
uvproject is structured - Which common
pipand Poetry tasksuvreplaces - How to start a new project with
uv - How to migrate from
requirements.txtwithout changing everything at once - When
pipor Poetry is still the better fit
Why uv Keeps Coming Up in 2026
According to the official uv documentation, the tool aims to replace parts of pip, pip-tools, pipx, poetry, pyenv, and virtualenv in one workflow. That sounds like a big promise, but the pieces line up once you look at how uv treats a project.
A uv project usually revolves around four files or directories:
| File | What it does |
|---|---|
pyproject.toml | Stores project metadata and dependency declarations |
uv.lock | Stores the exact resolved dependency set |
.python-version | Pins the default Python version for the project |
.venv | Holds the project environment, created and managed by uv |
That setup gives you one source of truth for declared dependencies and one lockfile for reproducible installs. Astral’s docs also note that uv.lock is cross-platform, which matters if your team moves between macOS, Linux, and Windows.
The part many developers end up liking most is that uv keeps the workflow close to the project folder. You do not have to remember as much shell state. You run a command, and uv makes sure the environment and lockfile match the project.
Starting a New Python Project With uv
The official installer uses a shell script, though uv can also be installed with pip. Once it is available on your machine, the basic flow is short:
uv init demo-api
cd demo-api
uv add fastapi pydantic
uv add --dev pytest ruff
uv run python -c "import fastapi; print(fastapi.__version__)"
After uv init, you get a starter project with pyproject.toml, README.md, .python-version, and a sample main.py. The first time you run a project command such as uv add, uv sync, or uv run, uv also creates .venv and uv.lock.
A minimal pyproject.toml ends up looking like this:
[project]
name = "demo-api"
version = "0.1.0"
description = "Sample API"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115.0",
"pydantic>=2.10.0",
]
[dependency-groups]
dev = [
"pytest>=8.0.0",
"ruff>=0.11.0",
]
That is a cleaner starting point than juggling requirements.txt, requirements-dev.txt, and a separate note about which Python version the project expects.
If you are building APIs, the uv run step is where the workflow starts to feel good. You can do this without manually activating the environment:
uv run uvicorn main:app --reload
For teams that already use FastAPI production patterns or strong validation with Pydantic v2, that small change adds up. Fewer activation mistakes. Fewer vague onboarding steps.
uv vs pip Plus venv
pip is still the standard installer in the Python Packaging User Guide, and venv remains the standard manual way to isolate environments. That part has not changed. What has changed is how much work teams want to do by hand.
Here is the practical difference:
| Task | pip + venv | uv |
|---|---|---|
| Create an environment | python -m venv .venv | Created automatically during project commands |
| Activate the environment | Manual shell activation | Often unnecessary when using uv run |
| Add a dependency | pip install requests | uv add requests |
| Record dependencies | requirements.txt, pip freeze, or pip-tools | pyproject.toml plus uv.lock |
| Run a project command | Depends on active shell | uv run <command> |
| Lock for multiple platforms | Usually extra tooling or extra files | Built into uv.lock and universal resolution |
This does not make pip obsolete. It does make the older workflow feel more fragmented. In the classic flow, installation and declaration are easy to drift apart. A developer installs a package, forgets to update the right file, and the problem shows up later in CI.
uv closes that gap because uv add updates the declared dependency, the environment, and the lockfile in one move.
There is also a middle ground. Astral provides a uv pip interface for teams that want a faster, familiar CLI before adopting the full project workflow. The docs are clear about the trade-off: it is meant to cover common pip, pip-tools, and virtualenv workflows, but it is not a perfect clone of pip. That is a good reminder to test CI and installer behavior if your current setup depends on pip-specific configuration.
Where Poetry Still Feels Different
Poetry cleaned up Python project management long before uv arrived, and plenty of teams are happy there. Its official docs show a workflow built around isolated environments, poetry.lock, and a pyproject.toml configuration model that can use both [project] and [tool.poetry] sections.
The biggest day-to-day difference is not that Poetry is missing features. It is that Poetry still feels more package-first, while uv feels more general-purpose.
Poetry is comfortable when your team already lives in commands like these:
poetry add httpx
poetry install
poetry run pytest
poetry build
uv covers similar ground, but it does it with a flatter mental model. New app, library, CLI tool, or single script, the commands stay closer together:
uv add httpx
uv sync
uv run pytest
uv build
Poetry also keeps environment management as one of its core features. Its environment docs show commands for switching Python interpreters, activating environments, inspecting environment paths, and removing old environments. That is useful if your team wants explicit control over those steps.
If your team already has a mature Poetry workflow, do not migrate just because uv is newer. Tool churn is real. But for new projects, uv usually asks for fewer concepts on day one.
Migrating From requirements.txt Without Breaking Everything
This is the part that matters for real teams. Most Python projects are not greenfield projects. They already have requirements.txt, maybe requirements.in, maybe requirements-dev.txt, and maybe a Dockerfile that nobody wants to touch on Friday afternoon.
The good news is that Astral’s migration guide is practical. The recommended path starts with a pyproject.toml, then imports your existing dependency declarations.
A simple migration can look like this:
uv init
uv add -r requirements.in -c requirements.txt
That second command is the key detail. If you import only requirements.in, uv will resolve fresh versions. If you also pass -c requirements.txt, uv uses your locked versions as constraints so the initial migration is less disruptive.
If you have a development dependency file, the guide also shows this pattern:
uv add --dev -r requirements-dev.in -c requirements-dev.txt
That maps a split requirements workflow into a single pyproject.toml plus grouped dependencies. It is cleaner, and it is easier to review in Git.
There is one more detail worth knowing. Astral’s docs note that pip and pip-tools workflows often need separate lock outputs per platform. uv uses universal resolution for uv.lock, so you do not need a Linux lockfile and a Windows lockfile for ordinary project use. That can remove a quiet source of team friction.
If you are not ready for full migration, use uv pip first. If you are ready to clean up the project shape, move to uv add and uv.lock.
When uv Is the Better Default
uv is a strong default in these cases:
- New web apps, APIs, and internal services
- Cross-platform teams that want one lockfile
- Repositories that currently mix
pip,venv,pip-tools, and a few README incantations - CI pipelines where install speed and repeatability matter
- Teams that want a single tool for Python versions, environments, dependencies, and scripts
There is also a platform signal here, not just hype. In a November 12, 2025 Azure App Service for Linux update, Microsoft said its build pipeline now detects pyproject.toml and uv.lock and performs automatic uv builds. That does not prove every team should switch, but it does show uv is moving beyond personal preference and into deployment tooling.
When to Keep pip or Poetry
Keep pip if the goal is minimal change. Maybe you have stable CI, simple apps, and a team that already understands requirements.txt inside out. In that case, using the standard installer and venv is still a valid choice. There is no prize for rewriting a stable setup.
Keep Poetry if your team is invested in its workflow and release habits. If people already know poetry install, poetry lock, poetry build, and your automation relies on that behavior, the migration cost may be larger than the benefit.
Stay cautious if your current process depends on pip-specific configuration files or uncommon installer behavior. Astral’s compatibility docs make it clear that uv aims for common workflow parity, not bug-for-bug parity with pip.
That is the real rule here: pick the tool that reduces friction for your team, not the one with the best benchmark screenshot.
A Sensible uv Workflow for Most Teams
If you were starting a typical Python application today, this is a reasonable flow:
uv init --package service-api
cd service-api
uv add fastapi pydantic httpx
uv add --dev pytest ruff mypy
uv run pytest
uv run ruff check
uv run mypy src
uv build
That gives you declared dependencies in pyproject.toml, exact versions in uv.lock, a local project environment in .venv, and no need to remember shell activation for every task. One tool handles both development and packaging steps.
It is a good fit for small apps and for larger services. The same workflow also scales well into Docker and CI because uv lock and uv sync are built into the core model, not bolted on later.
Summary
uv is not magic. It is just a better-organized answer to a set of chores Python developers have been repeating for years.
pip is still the standard installer. venv is still the standard manual environment tool. Poetry is still a solid choice for teams that already depend on its workflow. But if you are starting a new project in 2026, uv is the tool most teams should try first.
It gives you one place to declare dependencies, one lockfile to commit, one command style for running project tasks, and a realistic migration path from older requirements.txt workflows. That is enough to make daily Python work feel calmer, which is often more valuable than any headline speedup.
For related reading, see our guides on Python best practices, FastAPI async patterns, and Pydantic v2.
Sources:
- uv official overview
- uv project workflow guide
- uv migration guide from pip to projects
- uv pip interface docs
- Python Packaging User Guide: pip and virtual environments
- Python Packaging User Guide: tool recommendations
- Poetry docs: managing environments
- Poetry docs: pyproject.toml
- Microsoft Azure App Service update on uv support, published 2025-11-12
Discussion
Leave a comment
No comments yet
Be the first to start the conversation.