What is pyproject.toml file for?
Categories:
Understanding pyproject.toml: The Modern Python Project Configuration

Explore the purpose and structure of the pyproject.toml
file, a central configuration hub for Python projects, packaging, and tooling.
The pyproject.toml
file has emerged as the standard and recommended way to configure Python projects. Introduced by PEP 518 and later expanded by PEP 621, it provides a single, centralized location for build system requirements, project metadata, and tool-specific configurations. This article will delve into what pyproject.toml
is, why it's important, and how to use it effectively for your Python projects.
The Evolution of Python Project Configuration
Historically, Python projects relied on setup.py
and setup.cfg
for packaging and distribution. While functional, this approach had limitations, particularly when it came to specifying build-time dependencies and standardizing tool configurations. The introduction of pyproject.toml
aimed to solve these issues by providing a declarative, static, and tool-agnostic configuration format based on the TOML (Tom's Obvious, Minimal Language) specification.
flowchart TD A[Old Way: setup.py/setup.cfg] --> B{Build System Selection} B --> C[New Way: pyproject.toml] C --> D[Standardized Build Requirements] C --> E[Centralized Tool Config] D --> F[Improved Dependency Management] E --> G[Simplified Project Setup] F & G --> H[Modern Python Packaging]
Evolution from traditional Python packaging to pyproject.toml
Key Sections and Their Purpose
A pyproject.toml
file is structured into various sections, each serving a distinct purpose. The most common and important sections include [build-system]
, [project]
, and tool-specific tables like [tool.poetry]
, [tool.flit]
, [tool.hatch]
, [tool.setuptools]
, [tool.black]
, or [tool.mypy]
.
pyproject.toml
is valid TOML syntax. Tools like toml-cli
can help validate your file.The [build-system]
Table
This is often the first section you'll encounter in a pyproject.toml
file. It specifies the build backend that your project uses to create distributable packages (like wheels or source distributions). This section is crucial because it tells pip
and other installers how to build your project before they can install it.
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
Example [build-system]
configuration using Setuptools
requires
: A list of packages that must be installed before the build backend can be imported. These are build-time dependencies.build-backend
: The entry point for the build backend. This tells the installer which module and function to call to perform the build.
The [project]
Table (PEP 621 Metadata)
The [project]
table, standardized by PEP 621, allows you to declare all your project's core metadata directly in pyproject.toml
. This includes the project name, version, description, authors, dependencies, and more. This eliminates the need for setup.py
or setup.cfg
for basic metadata, making project configuration more declarative and less reliant on executable code.
[project]
name = "my-awesome-package"
version = "0.1.0"
authors = [
{ name="John Doe", email="john.doe@example.com" },
]
maintainers = [
{ name="Jane Smith", email="jane.smith@example.com" },
]
description = "A short description of my awesome package."
readme = "README.md"
requires-python = ">=3.8"
license = { file="LICENSE" }
keywords = ["python", "packaging", "example"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
dependencies = [
"requests>=2.28.1",
"rich~=12.0",
]
[project.urls]
"Homepage" = "https://github.com/my-org/my-awesome-package"
"Bug Tracker" = "https://github.com/my-org/my-awesome-package/issues"
[project.scripts]
my-cli = "my_package.cli:main"
Example [project]
table with common metadata fields
Key fields in [project]
:
name
: The name of your package.version
: The package version.authors
,maintainers
: Contact information for the project.description
,readme
: Short and long descriptions of the project.requires-python
: The Python versions your package supports.license
: Licensing information.dependencies
: Runtime dependencies of your package.[project.urls]
: Links to project resources.[project.scripts]
: Entry points for command-line scripts.
Tool-Specific Configuration Tables
Beyond the standardized [build-system]
and [project]
tables, pyproject.toml
also serves as a central place for configuring various Python development tools. This is done using tables prefixed with [tool.]
, followed by the tool's name. This approach prevents configuration sprawl across multiple dotfiles and provides a consistent way to manage project settings.
[tool.black]
line-length = 88
target-version = ['py38', 'py39', 'py310']
include = '\.pyi?$'
exclude = '''
/(.
| .venv
| migrations
)/
'''
[tool.mypy]
python_version = "3.9"
warn_unused_configs = true
ignore_missing_imports = true
[tool.pytest.ini_options]
min_version = "6.0"
addopts = "--strict-markers --strict-files"
xfail_strict = true
filterwarnings = [
"error",
"ignore::DeprecationWarning",
]
Examples of tool-specific configurations for Black, MyPy, and Pytest
Common tools that leverage pyproject.toml
for configuration include:
- Formatters:
black
,isort
- Linters:
flake8
,pylint
- Type Checkers:
mypy
- Test Runners:
pytest
- Packaging Tools:
poetry
,flit
,hatch
,setuptools
(for advanced options)
By consolidating these configurations, pyproject.toml
makes it easier to onboard new developers, ensure consistent development practices, and manage project settings.
[tool.<tool_name>]
tables are entirely dependent on the tool itself. Always refer to the official documentation of each tool for its pyproject.toml
configuration options.