Python uv Core Concepts: pyproject.toml, Lockfile & Virtual Environments

3 min read

Before typing commands at random, get these four concepts into your head: you'll be clearer on "where do dependencies go, what's the lockfile for, when does the venv get created." Like reading the skill descriptions before playing a game — otherwise you'll keep dying for no reason.

Concept 1: pyproject.toml Is Your Project's ID Card

Project metadata and dependencies all live here — it's the PEP 518 standard format.

[project]
name = "my-app"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "requests>=2.31",
]
  • Manual editing: edit pyproject.toml directly
  • Command-driven: uv add requests and uv remove requests update it automatically

Don't mix methods — either edit manually or use commands. Doing both causes conflicts.

Concept 2: uv.lock Is a Dependency Snapshot

pyproject.toml says "what I want" (e.g. requests>=2.31). uv.lock records "what was actually installed" — precise down to every transitive dependency.

  • Why have a lockfile? Ensures everyone — all teammates, CI, production — installs the exact same dependency tree. No more "it works on my machine, it breaks on yours."
  • Should you commit it? Yes. uv.lock should be in version control so the team and CI use the same dependency tree.
# Update the lockfile (e.g. upgrade a package)
uv lock --upgrade-package requests

Concept 3: .venv Is Your Project's Sandbox

uv creates .venv in the project root — all uv add packages go in here, isolated from the system Python.

  • Do you need to manually activate it? No. uv run automatically uses this environment.
  • Should you commit it? No. .venv should be in .gitignore.
# Manually sync the environment (e.g. after a fresh clone)
uv sync
source .venv/bin/activate  # after this you can use python, pytest, etc. directly

Concept 4: uv run Is the Effortless Entry Point

uv run will:

  1. Check if the lockfile is consistent with pyproject.toml
  2. Ensure .venv is in sync with the lockfile
  3. Execute your specified command in the correct environment
uv run python main.py
uv run pytest
uv run flask run -p 3000

No need to remember to activate, no worrying about the wrong environment — just hand it to uv. Like a cat that always finds the litter box without thinking about it. Once you experience this "just run it" feeling, there's no going back.

Next Steps

Once you've absorbed the core concepts, head into the high-frequency operations: dependency management, uvx, script execution. 👉 Common Patterns