Understanding pyproject.toml, setuptools, .whl, and .tar.gz
June 15, 2026
Today I learned how modern packaging works in Python.
1. pyproject.toml
pyproject.toml is the main configuration file for a Python project.
It tells Python tools:
- project name
- version
- dependencies
- how to build the package
Very similar to:
package.jsonin Node.jspom.xmlin Apache Maven
Example: pyproject.toml
[project]
name = "mypackage"
version = "1.0.0"
dependencies = [
"fastapi",
"uvicorn"
]
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"This does not install dependencies by itself. It only declares them for your project.
Earlier Python packaging was messy and spread across files like:
setup.pyrequirements.txt
Now it is centralized in pyproject.toml.
How dependencies get installed
Once dependencies are declared in pyproject.toml, installer tools (usually pip) read them during install.
Common commands:
pip install .pip install -e .pip install .installs your package and its declared dependenciespip install -e .does the same in editable mode for local development
If you define optional groups (like dev), you can install them with:
pip install -e ".[dev]"2. What setuptools does
setuptools is the tool that converts Python code into installable/distributable packages.
Think:
Your code -> setuptools -> distributable artifactSimilar to:
- Maven/Gradle packaging in Java
Example project
myproject/
|
|- pyproject.toml
`- src/
`- mypackage/
|- __init__.py
`- math_utils.py3. Building the package
Command:
python -m buildWhat this does under the hood:
- Reads
pyproject.toml - Looks at
[build-system] - Uses the build backend declared there (
setuptools.build_metain this case) - Creates distribution artifacts in
dist/(.whland.tar.gz)
So yes, if pyproject.toml says:
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"then python -m build will use that backend to build your package.
Output
A new folder gets created:
dist/
|
|- mypackage-1.0.0.whl
`- mypackage-1.0.0.tar.gz4. What are these files?
.whl (Wheel)
Example:
mypackage-1.0.0-py3-none-any.whlThis is the main installable package format in Python.
Equivalent to:
JAR artifact in JavaUsers install it using:
pip install mypackage-1.0.0.whl.tar.gz
This is the source distribution.
Contains:
- raw source code
- project files
Used when:
- wheel unavailable
- package needs platform-specific compilation
5. Important difference from Java
In Java:
.jarusually contains compiled.classbytecode
In Python:
.whloften contains actual.pysource files
because Python is mostly interpreted.
Example wheel contents:
mypackage/
__init__.py
math_utils.pySome libraries like NumPy may also include compiled binaries (.so, .dll) for performance.
PyPI or internal registry
After build, these artifacts are usually published to:
- PyPI (public Python package index), so anyone can install using
pip - Internal registry (private company package repo), so only your org can use it
Then consumers install from that registry using pip install ....