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 (“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 # ///:
# /// 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 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 sees uv run fetch_stars.py, it:
- Parses the
# /// scriptblock. - Resolves the dependency list against a package index.
- Creates a cached temporary environment with the resolved packages.
- 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 runs scripts with
uv run script.pyand scaffolds the metadata block withuv add --script script.py requests. - pipx runs scripts with
pipx run script.py. - Hatch and PDM run scripts via
hatch runandpdm run. - pip 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 project with a lockfile is the better choice. See Do I need a project to use uv? for a comparison of all the options.