The pyproject.toml Builder generates a modern, PEP 621 compliant project file — the single configuration file that replaces setup.py, setup.cfg and requirements.txt for packaging. Enter your metadata and dependencies and the tool emits a complete [build-system] and [project] block plus extras, a script entry point and basic tool config.
How it works
Two tables do the core work. [build-system] (PEP 517) names the backend pip uses to build a wheel — Hatchling, setuptools, Flit or Poetry core — so a fresh environment can build your package with nothing installed globally. [project] (PEP 621) holds the metadata PyPI displays: name, version, description, requires-python, license, authors and the dependencies list.
The tool also adds [project.optional-dependencies] with a dev extra (pytest, ruff, mypy), an optional [project.scripts] console entry point, project URLs, and starter [tool.ruff] / [tool.mypy] sections. The package name is normalised to a valid PyPI distribution name, and the import module name is derived by replacing hyphens with underscores.
Example generated file
For a package named my-data-tool with one dependency:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-data-tool"
version = "0.1.0"
description = "A data processing utility"
requires-python = ">=3.10"
dependencies = [
"httpx>=0.27",
]
[project.optional-dependencies]
dev = [
"pytest>=8",
"ruff>=0.4",
"mypy>=1.10",
]
[project.scripts]
my-data-tool = "my_data_tool.__main__:main"
[tool.ruff]
line-length = 88
[tool.mypy]
strict = true
The name my-data-tool becomes the distribution name on PyPI, while the import module is my_data_tool (hyphens converted to underscores). The console script maps the command my-data-tool to my_data_tool.__main__:main.
Example workflow
Once you have a pyproject.toml and a source package, build and install like this:
python -m build # produces dist/*.whl and *.tar.gz
pip install -e ".[dev]" # editable install with the dev extra
Choosing a build backend
| Backend | Best for | Notes |
|---|---|---|
| Hatchling | Pure-Python modern packages | Fast, good defaults, no legacy config |
| setuptools | Packages with C extensions | Most widely supported; needed for ext_modules |
| Flit | Minimal pure-Python packages | Very simple; no extras support in core |
| Poetry core | Projects already using Poetry | Consistent with pyproject.toml-only workflow |
All four produce standard wheels that pip install accepts.
Tips and notes
A console script such as mypkg = mypkg.__main__:main requires a __main__.py that defines a main() function — the generated entry point assumes that layout. Keep runtime dependencies lean in dependencies and push test or build tooling into extras, so end users do not pull in your whole toolchain. For reproducible builds, pair this with a lock file from uv, pip-tools or Poetry.
The requires-python specifier protects users from installing on an incompatible interpreter — always set it. A specifier like >=3.10 is both honest and forward-compatible; ==3.10.* is unnecessarily narrow unless you have tested and rely on a specific minor version.