Skip to main content
Projects help manage Python code spanning multiple files. Working on projects is a core part of the uv experience.
Looking for an introduction to creating a project with uv? See the projects guide first.

Project Structure

A uv project requires a pyproject.toml file that defines project metadata and dependencies.

Minimal Project Definition

A minimal project definition includes a name and version:
pyproject.toml
[project]
name = "example"
version = "0.1.0"

Complete Project Structure

A typical uv project includes:
  • pyproject.toml - Project metadata, dependencies, and configuration
  • uv.lock - Universal lockfile with exact package versions
  • .venv/ - Virtual environment (auto-managed by uv)
  • src/ or flat structure - Python source code

The pyproject.toml File

Python project metadata is defined in a pyproject.toml file following the PEP 621 standard. uv uses this file to identify the project root directory.

Project Metadata

Additional project metadata includes:
pyproject.toml
[project]
name = "albatross"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
  "tqdm >=4.66.2,<5",
  "torch ==2.2.2",
  "transformers[torch] >=4.39.3,<5",
]

Key Metadata Fields

  • name - Package name
  • version - Package version
  • requires-python - Python version requirement
  • dependencies - Runtime dependencies
  • optional-dependencies - Optional feature dependencies (extras)

Python Version Requirement

The requires-python field determines:
  • Python syntax allowed in the project
  • Compatible dependency versions (must support the same Python range)
pyproject.toml
[project]
name = "example"
version = "0.1.0"
requires-python = ">=3.12"

The Project Environment

When working on a project, uv automatically creates and manages a virtual environment.

Default Environment Location

By default, uv creates a persistent environment in a .venv directory next to pyproject.toml. The .venv directory:
  • Makes it easy for editors to find (for code completions and type hints)
  • Is automatically excluded from git (via internal .gitignore)
  • Should not be included in version control

Running Commands

To run a command in the project environment:
uv run python script.py
Alternatively, activate the environment manually:
source .venv/bin/activate  # Unix
.venv\Scripts\activate     # Windows
Do not modify the project environment manually with uv pip install. Use uv add for project dependencies or uv run --with for one-off requirements.

Auto-Sync Behavior

When uv run is invoked:
  1. Creates the project environment if it doesn’t exist
  2. Ensures the environment is up-to-date with lockfile
  3. Runs the requested command
To disable auto-sync:
uv run --no-sync <command>

Custom Environment Path

The UV_PROJECT_ENVIRONMENT environment variable configures the virtual environment path:
# Relative to workspace root
export UV_PROJECT_ENVIRONMENT=.venv

# Absolute path
export UV_PROJECT_ENVIRONMENT=/path/to/env
If using an absolute path across multiple projects, the environment will be overwritten by each project. Only recommended for single projects in CI or Docker.

The Lockfile

uv creates a uv.lock file next to pyproject.toml that captures exact package versions.

Universal Lockfile

uv.lock is a universal or cross-platform lockfile that includes packages for all possible Python markers:
  • Operating systems (Linux, macOS, Windows)
  • Architectures (x86_64, aarch64)
  • Python versions (3.9, 3.10, 3.11, etc.)

Lockfile vs pyproject.toml

pyproject.toml

  • Broad requirements
  • Version constraints
  • Manually edited

uv.lock

  • Exact versions
  • Resolved dependencies
  • Auto-managed by uv

Version Control

The lockfile should be checked into version control because it:
  • Ensures consistent package versions across developers
  • Guarantees reproducible installations
  • Locks exact versions for production deployments

Auto-Update Behavior

The lockfile is automatically created and updated during:
  • uv sync - Sync environment with lockfile
  • uv run - Run command in project environment
  • uv lock - Explicitly update lockfile
uv.lock is human-readable TOML but should not be edited manually. It uses a uv-specific format not compatible with other tools.

Virtual Environments

Virtual environments isolate project dependencies from the system Python.

Creating Environments

The project environment is automatically created when needed:
# Auto-creates .venv if needed
uv run python script.py

# Explicitly create/sync environment
uv sync
To manually create a virtual environment:
uv venv

Editable Installation

By default, when the environment is synced, uv installs the project as an editable package:
  • Source code changes are immediately reflected
  • No need to re-sync after editing files
  • Uses .pth file to link source directory
To opt-out of editable installation:
uv sync --no-editable
If the project doesn’t define a build system in [build-system], it won’t be installed as a package.

Managed vs Unmanaged Projects

By default, uv manages the project environment automatically. To disable this:
pyproject.toml
[tool.uv]
managed = false
With managed = false, uv will not automatically lock or sync the project.

Build Systems

A build system determines how the project should be packaged and installed.

When to Use Build Systems

You probably need a build system if you want to:
  • Add command-line interfaces
  • Distribute the project to others
  • Use a src/ and test/ layout
  • Write a library
You probably don’t need a build system if you’re:
  • Writing simple scripts
  • Building a basic application
  • Using a flat layout

Defining a Build System

pyproject.toml
[project]
name = "example"
version = "0.1.0"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Build Backend Options

Common build backends include:
  • hatchling - Modern, fast build backend
  • setuptools - Traditional, widely-used
  • flit - Lightweight for simple packages
  • pdm-backend - PDM’s build backend
Create a packaged project with a specific backend:
uv init --build-backend hatchling

# Or use default backend
uv init --package

Package Setting Override

Override the automatic build system detection:
pyproject.toml
[tool.uv]
# Force building even without build-system
package = true

# Or prevent building despite build-system
package = false

Entry Points

Entry points allow installed packages to advertise interfaces.

Command-Line Interfaces

Define CLI commands in [project.scripts]:
pyproject.toml
[project.scripts]
hello = "example:main"
process = "example.cli:process_data"
Run commands with:
uv run hello
uv run process --input data.csv

GUI Scripts

Define GUI applications in [project.gui-scripts]:
pyproject.toml
[project.gui-scripts]
app = "example:launch_gui"
GUI scripts differ from CLI scripts only on Windows, where they’re wrapped by a GUI executable to run without a console.

Plugin Entry Points

Register plugins for discovery:
pyproject.toml
[project.entry-points.'myapp.plugins']
foo = "example_plugin_foo"
bar = "example_plugin_bar"
Load plugins in your application:
from importlib.metadata import entry_points

for plugin in entry_points(group='myapp.plugins'):
    plugin.load()

Managing Dependencies

Learn how to add, remove, and manage project dependencies

Python Versions

Understand Python version management and installation

Workspaces

Work with multiple related projects in a single repository

Caching

Learn about uv’s caching mechanisms for faster installs

Build docs developers (and LLMs) love