# What is PEP 723?

Before PEP 723, a single-file Python script that needed third-party packages had no self-contained way to say so. The author could add a `requirements.txt` next to the file or write install instructions in a comment, but both broke when someone moved the script to a different machine.

[PEP 723](https://peps.python.org/pep-0723/) ("Inline script metadata") solves this by defining a commented TOML block that lives inside the script itself. A compatible runner reads the block, builds a temporary environment with the listed packages, and executes the script without a project directory or manual `pip install`.

## What the metadata block looks like

The block starts with `# /// script`, contains TOML, and ends with `# ///`:

```python {filename="fetch_stars.py"}
# /// script
# requires-python = ">=3.10"
# dependencies = [
#     "requests>=2.31",
# ]
# ///

import requests

repo = "astral-sh/uv"
stars = requests.get(f"https://api.github.com/repos/{repo}").json()["stargazers_count"]
print(f"{repo}: {stars:,} stars")
```

The two recognized keys are `requires-python` (a version specifier) and `dependencies` (a list of [PEP 508](https://peps.python.org/pep-0508/) requirement strings, including extras and environment markers). The block is valid TOML with every line prefixed by `#`, so editors that understand TOML can syntax-highlight it and the Python interpreter ignores it.

## How runners use it

When [uv](https://pydevtools.com/handbook/reference/uv.md) sees `uv run fetch_stars.py`, it:

1. Parses the `# /// script` block.
2. Resolves the dependency list against a package index.
3. Creates a cached temporary environment with the resolved packages.
4. Runs the script inside that environment.

Subsequent runs reuse the cached environment as long as the metadata block and the Python version haven't changed.

## Tools that support PEP 723

- [uv](https://pydevtools.com/handbook/reference/uv.md) runs scripts with `uv run script.py` and scaffolds the metadata block with `uv add --script script.py requests`.
- [pipx](https://pydevtools.com/handbook/reference/pipx.md) runs scripts with `pipx run script.py`.
- [Hatch](https://pydevtools.com/handbook/reference/hatch.md) and [PDM](https://pydevtools.com/handbook/reference/pdm.md) run scripts via `hatch run` and `pdm run`.
- [pip](https://pydevtools.com/handbook/reference/pip.md) 26.0 (January 2026) added `--requirements-from-script`, which installs the declared dependencies into the current environment without running the script.

## When to use inline metadata vs. a project

Inline metadata fits scripts that travel alone: automation snippets, one-off data pulls, gist-shared utilities. If the script imports first-party modules from a package on disk, or if multiple scripts share a dependency set worth locking together, a [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md) project with a [lockfile](https://pydevtools.com/handbook/explanation/what-is-a-lock-file.md) is the better choice. See [Do I need a project to use uv?](https://pydevtools.com/handbook/explanation/do-i-need-a-project-to-use-uv.md) for a comparison of all the options.

## Learn More

- [PEP 723 specification](https://peps.python.org/pep-0723/)
- [How to write self-contained Python scripts using PEP 723](https://pydevtools.com/handbook/how-to/how-to-write-a-self-contained-script.md)
- [How to convert a script with requirements.txt to PEP 723 inline metadata](https://pydevtools.com/handbook/how-to/how-to-convert-a-script-with-requirements-txt-to-pep-723-inline-metadata.md)
- [Inline script metadata specification](https://packaging.python.org/en/latest/specifications/inline-script-metadata/)
- [uv guide: declaring script dependencies](https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies)
