Initialize a UV Python Project

With UV we will manage our Python environment

Initializing a New Project

To get started, open your terminal and run uv init followed by your desired project name; uv will create a new directory and initialize a pyproject.toml file according to the PEP 621 specification. For example, executing uv init hello-world generates a folder named hello-world and populates it with a minimal scaffolding including a pyproject.toml, a simple main.py, and a .python-version file that pins your interpreter version.

If you omit the path argument, uv assumes the current directory is the target and initializes the project in place, allowing you to transform any existing folder into a UV-managed project. Behind the scenes, uv also runs git init, creates a .gitignore file, and adds a README.md stub so that your project is immediately version-controlled with sensible defaults out of the box. Should you wish to create a standalone library instead of an application, adding the --lib flag instructs uv to generate a package layout under a src directory and adjust the pyproject metadata accordingly.

Advanced users can supply flags such as -p (or --python) to pin a specific Python interpreter version—e.g., uv init -p 3.13 myproj will configure the project to use Python 3.13 and record this in the auto-generated .python-version file. If uv detects an existing pyproject.toml in any parent directory, it will automatically add the new project as a workspace member unless you disable this behavior with --no-workspace. Importantly, certain project artifacts, like the virtual environment folder and lockfile, are created lazily when you next invoke uv sync or run any project script, keeping the initial scaffold lightweight and fast.

Understanding the pyproject.toml File

The pyproject.toml file serves as a universal configuration hub for modern Python projects, unifying build requirements, project metadata, and tool-specific settings under a single, human-readable format. Introduced in PEP 518 and formally extended by PEP 621, this file leverages the TOML language to declare everything from build-system dependencies to version constraints and even custom CLI scripts for tools like UV . By consolidating configuration into pyproject.toml, projects gain clearer structure, reproducible builds, and simpler collaboration across diverse environments.

Structure and Purpose

At its core, pyproject.toml is divided into three reserved tables: [build-system], [project], and [tool]. The [build-system] table lists the minimal dependencies required to bootstrap your project’s build process, typically a build backend like setuptools or flit . The [project] table encapsulates metadata such as name, version, description, license, and runtime dependencies, replacing legacy files like setup.py and setup.cfg with a declarative, standardized format . Finally, the [tool] table is a catch-all namespace for tool-specific configurations; UV places its settings under [tool.uv], where you can define dependency groups, lockfile behavior, and interpreter constraints without altering the other sections .

TOML Syntax and Comparison with JSON

TOML (Tom’s Obvious, Minimal Language) is designed for clarity and ease of parsing, featuring straightforward key = value assignments, clearly delimited tables, and native support for types like integers, floats, booleans, datetimes, arrays, and nested tables . Unlike JSON, which requires all keys and string values to be quoted and uses braces and brackets exclusively for structure, TOML permits unquoted keys when they match identifier rules, supports inline tables for concise grouping, and allows comments with #, making it far more human-friendly for configuration . Whereas JSON is purely data-centric, lacking comments and requiring strict syntax, TOML’s design balances machine-parsability with readability, enabling maintainers to annotate settings and organize complex configurations in a natural, hierarchical fashion .

UV-Specific Configuration Sections

Within the [tool.uv] namespace, UV leverages TOML’s expressive power to let you declare environment behavior and dependency groups directly alongside your project metadata. Here, you can specify default Python versions, custom indexes, and extras that should be installed in different scenarios (e.g., testing versus production) without touching platform-specific files like requirements.txt . UV also writes its own lockfile (uv.lock) in tandem with pyproject.toml, freezing exact package versions to guarantee reproducible environments across machines and CI pipelines . By editing pyproject.toml or running UV commands like uv add and uv sync, the file remains the single source of truth for all aspects of your project’s lifecycle, from initial setup to deployment.

Last updated