Pyproject.toml: The Ultimate Guide to Python Packaging in 2026
For years, the Python packaging world was a Wild West of setup.py, setup.cfg, and requirements.txt. It was messy, often insecure, and required executing arbitrary Python code just to install a library.
In 2026, pyproject.toml is the undisputed king. It is a single, human-readable configuration file that tells Python exactly how to build, install, and manage your project.
🏗️ The Anatomy of pyproject.toml
Think of this file as the "Birth Certificate" for your code. It defines your project's identity and its relationship with the rest of the Python ecosystem.
1. The Build System (The Engine)
This section tells pip which "backend" to use to turn your code into a distributable file (a Wheel or an Sdist).
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
2. Project Metadata (The Identity)
This is the information that appears on PyPI (the Python Package Index).
[project]
name = "my_cool_library"
version = "1.0.0"
description = "A library that does amazing things"
readme = "README.md"
requires-python = ">=3.9"
authors = [
{name = "Your Name", email = "you@example.com"}
]
dependencies = [
"requests>=2.28.0",
"numpy>=1.22.0",
]
3. Entry Points (The CLI Trigger)
Remember our talk about __main__.py? You can use pyproject.toml to create a permanent command that users can type in their terminal after installing your package.
[project.scripts]
cool-tool = "my_cool_library.__main__:main"
Now, instead of typing python -m my_cool_library, your users can just type cool-tool.
🛠️ The "Local Install" Workflow
Before you upload your code to the world, you need to test it locally. The best way to do this is with an Editable Install.
-
Navigate to your project folder (where
pyproject.tomllives). -
Run this command:
pip install -e .The
-e(editable) flag is magic. It links the installation to your source code. If you change a line in your.pyfile, the "installed" version updates instantly without needing a reinstall.
📊 Why This is Better than setup.py
| Feature | setup.py (Legacy) | pyproject.toml (2026 Standard) |
|---|---|---|
| Format | Executable Python Code | Declarative TOML |
| Security | Low (Runs code on install) | High (Static configuration) |
| Tooling | Tied to Setuptools | Works with Poetry, Hatch, Flit, etc. |
| Readability | Can get messy/complex | Clean and structured |
🛡️ Best Practices for 2026
-
Version Pinning: Use "compatible release" operators like
requests >= 2.28.0, < 3.0.0. This ensures your library doesn't break when a dependency releases a massive, breaking update. -
Optional Dependencies: Use "Extras" for features that not everyone needs (like database drivers or plotting tools).
[project.optional-dependencies]
dev = ["pytest", "black", "mypy"]
plotting = ["matplotlib"] -
The
srcLayout: Many pros put their code in asrc/subdirectory. This forces you to test the installed version of your code rather than the local folder, catching import errors early.
📚 Sources & Technical Refs
- [1.1] Python Packaging User Guide: Writing pyproject.toml - The official standard.
- [2.1] PEP 621: Storing project metadata - The technical specification for the
[project]table. - [3.1] Setuptools Docs: Configuring with pyproject.toml - Specifics for the most common build backend.
