Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
pyproject.toml (PEP 518/621) is the standard project manifest in 2026 — it replaces setup.py, setup.cfg, Pipfile, and the bespoke configs of 90% of tools. It carries project metadata, dependencies, build backend, and tool config (ruff, mypy, pytest all read from it). A fresh project in 2026 has one pyproject.toml and that's it — no setup.py, no setup.cfg. Knowing every section by heart is the difference between 'I copy from a template' and 'I can ship a Python library to PyPI'.
pyproject.toml is the single source of truth for a Python project: it declares direct dependencies, the required Python version, build backend, optional dependency groups (like dev), and the configuration of every tool (ruff, mypy, pytest) that reads from it. Before PEP 518/621 you needed setup.py, setup.cfg, MANIFEST.in, tox.ini, and a bespoke requirements-dev.txt — all of which are now replaced by one file. A production-grade pyproject.toml also declares [project.scripts] entry points so that pip install automatically wires up CLI binaries on the user's PATH.
# pyproject.toml
[project]
name = "myapp"
version = "0.1.0"
description = "A FastAPI service"
requires-python = ">=3.12"
authors = [{ name = "You", email = "you@example.com" }]
readme = "README.md"
license = "MIT"
dependencies = [
"fastapi>=0.110",
"uvicorn[standard]>=0.29",
"httpx>=0.27",
"pydantic-settings>=2.2",
]
[project.optional-dependencies]
dev = [
"pytest>=8",
"pytest-asyncio>=0.23",
"ruff>=0.4",
"mypy>=1.10",
]
[project.scripts]
myapp = "myapp.cli:main" # `pip install` will create a `myapp` binary
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.ruff]
line-length = 100
target-version = "py312"
[tool.mypy]
python_version = "3.12"
strict = truepython3 main.pyuv pip install -e . (editable install) and confirm pip list shows your package.[project.scripts] entry pointing at a function in your code. Re-install. Now there's a CLI binary on your PATH.[tool.ruff] section. Run ruff check . — it picks up the config automatically. This is the new standard.uv pip install -e ".[dev]" to install with optional deps. This is how dev-only deps stay out of production.Use these three in order. Each builds on the one before.
In one paragraph, explain what `pyproject.toml` replaces and why every Python project should be using it by 2026.
Walk me through `[build-system]` and the difference between hatchling, setuptools, poetry-core, and flit. Which should I default to and why?
I'm shipping a library to PyPI. What's the right way to model versioning, MSRV (`requires-python`), optional features, and CLI entry points? Show me the production-grade pyproject.toml.