The whole command becomes much easier to reason about once you stop treating it as magic and start treating it as an explicit handoff between environment preparation and target execution.
UV Series
uv Actually Does in a Python Workflow
A rigorous mental model for understanding how uv coordinates project metadata, environments, lockfiles, and commands.
Read article
2
Starting a Project With uv init and Finding Your Bearings With uv help
How to move from a blank directory to a serious project structure without guessing what the tool is about to change.
Read article
3
uv pip and uv venv: Managing Packages and Isolating Environments
When to use the low-level pip-compatible interface, and when to stay in uv's higher-level project workflow.
Read article
4
How uv run Works, Including flet build and flet run
A precise account of where uv's responsibility ends and the invoked command's responsibility begins.
Current article
5
Using uv tool to Install and Run Python-Based Commands
How to decide between user-wide tools, one-off ephemeral tools, and project-pinned developer dependencies.
Read article
6
Miniconda vs uv: Which One Should You Use for Python Projects?
A problem-first comparison between environment-first Conda workflows and Python-project-first uv workflows.
Read article
uv run prepares the project context, then hands control to the command you actually want to run.
The python-uv repo uses uv run for nox, pytest, ruff, ty, pre-commit, and MkDocs.
You should leave able to identify exactly which part of a command line belongs to uv and which part does not.
uv run Prepares the Context. The Target Command Owns the Rest.
The best explanation of uv run is also the simplest: it is the boundary between environment preparation
and actual execution. When you invoke uv run inside a project, uv ensures that the project
environment is up to date before it hands execution off to the target command.
That handoff model is what allows one command family to run Python entry points, external executables, linters, formatters, documentation servers, and even framework-specific build tools without becoming conceptually muddy.
uv owns preparation. The invoked command owns meaning.
How the Handoff Looks in a Serious Repository
In the python-uv repository, uv run is the standard entry point for ordinary work. But notice
what that means. uv is not “being” pytest, nox, ruff, ty,
or mkdocs. It is preparing the project environment in which those commands are then executed.
uv run nox -s test
uv run pytest tests/tools/test__logger.py
uv run ruff format .
uv run ruff check . --fix
uv run ty check
uv run mkdocs serve
Each line follows the same logic. uv run gives the command the correct project context; the command that
follows decides what happens after the handoff.
Why Flags Sometimes Seem to “Belong to the Wrong Tool”
Most confusion around uv run is really confusion about argument ownership. Options intended for
uv must appear before the target command. Everything after the command belongs to that command.
uv run --python 3.12 -- python -c "import sys; print(sys.version)"
uv run ruff check . --fix
uv run pytest -q
uv run mkdocs serve
In the first example, --python 3.12 belongs to uv. In the second, third, and fourth examples,
the options belong to the command that uv is running. This is not an incidental syntactic rule. It is the
consequence of the handoff model itself.
uv run guarantees
Why It Is Better Than “Just Activate the Environment and Hope”
In a project, uv run checks that the lockfile is current with respect to pyproject.toml and that
the environment is current with respect to the lockfile before it runs the command. That is why it is so useful in a team
setting: it reduces the number of silent ways contributors drift from the declared project state.
You can, of course, activate the virtual environment manually after uv sync. There is nothing unlawful about
that. But uv run is the cleaner default because it keeps execution tied to the project lifecycle rather than to
whatever state your shell happens to be in.
The Same Logic Applies to flet run and flet build
The title mentions Flet for a reason. It is an unusually good way to see the handoff clearly.
uv run flet run app.py
uv run flet build macos
In both examples, only uv run belongs to uv. The words flet, run,
build, and macos belong to Flet's command interface. Once you see that division, the mental model
becomes stable enough to generalize to any other tool.
uv is broken. It is whether the option was mentally assigned to the wrong command surface.
uv run Can Also Request Extra Dependencies for a Single Invocation
There is one more reason uv run deserves respect: it can temporarily request additional dependencies for a
single invocation.
uv run --with httpx==0.26.0 python -c "import httpx; print(httpx.__version__)"
That is a strong example of what uv is doing. It is not only running a command. It is shaping the
environment in which the command runs.
Frequently Asked Questions
These are the practical questions that a careful reader should be able to answer before treating the workflow as production-ready.
What does uv run do before executing a command in a project?
It ensures the project environment is up to date before handing execution off to the target command.
Who owns the flags after the target command name?
The target command does. Options intended for uv must appear before the command you are invoking.
Why use uv run instead of activating .venv manually?
Because it keeps execution tied to the project's declared and synchronized state instead of relying on ambient shell state.
What part of uv run flet build macos belongs to uv?
Only uv run. The rest belongs to Flet.
Can uv run add extra dependencies for one invocation?
Yes. The --with option can request additional dependencies or alternate versions for a single run.
References
Conclusion
The important habit is to read uv run as a handoff. Once you do, the command line stops feeling slippery: uv prepares the context, and the invoked tool owns the work that follows.
Comments