distribution

At some point, you’ll want to share your code, either with teammates inside your organization or with the wider Python community. A thoughtful distribution strategy makes it easy for others to install, upgrade, and use your project. It also helps you manage versions, dependencies, and metadata in a predictable manner, rather than relying on ad hoc scripts and manual instructions.

Modern Python packaging relies on the pyproject.toml file, which describes how your project is built and provides standard metadata, such as the project name, version, dependencies, entry points, and more. While some tools still support configuration in other files, pyproject.toml is now the central, standardized place for packaging configuration.

When it comes to packaging and distributing your Python projects, you should apply some of the best practices below:

  • Use pyproject.toml as the primary source of packaging configuration. Declare your project’s build settings and core metadata in pyproject.toml instead of relying on legacy setup.py scripts or scattered configuration files. This practice aligns with modern packaging standards (PEP 517 and PEP 621) and makes your build configuration easier to understand and maintain.
  • Choose a modern, standard-compliant build backend. Use a backend such as setuptools, Hatch (via hatchling), or poetry-core in your pyproject.toml. These backends implement modern packaging standards and allow other developers and tools to build your project without custom scripts. Typically, you choose one backend per project.
  • Version and tag releases consistently. Follow a clear versioning scheme like semantic versioning, and tag releases in your version control system. This practice helps users know when you’ve introduced new features, bug fixes, or breaking changes.
  • Be responsible about publishing to PyPI. Double-check metadata, dependencies, and licensing before uploading your packages to the Python Package Index (PyPI). Use a test index like TestPyPI to verify that your builds and installation instructions work as expected.
  • Document how to install your project. Provide copy-pasteable installation commands and clearly document any extra setup steps users need to take.

To see the difference that modern packaging makes, compare the following two approaches:

🔴 Avoid this:

The project layout:

resize-images/
└── resize_images.py

The source code:

Python resize_images.py
import sys
from pathlib import Path

def main():
    source = Path(sys.argv[1])
    target = Path(sys.argv[2])
    # Resize images logic here...

if __name__ == "__main__":
    main()

The installation and usage instructions:

Shell
$ git clone https://github.com/user/resize-tool.git
$ cd resize-tool/
$ python resize_images.py pictures/ thumbnails/

This project works, but it’s fragile. Users must clone the repository, navigate to the correct directory, and run the script directly with the python command. The project doesn’t declare standard metadata such as its name, version, or dependencies, and it can’t be installed or invoked using standard Python packaging tools or entry points.

Favor this:

The project layout:

resize-images/
├── src
│   └── image_tools
│       ├── __init__.py
│       └── cli.py
└── pyproject.toml

Using the src-layout helps prevent accidental imports from the project root during development and more closely matches how users will import your package once it’s installed.

The source code:

Python
import argparse
from pathlib import Path

def main() -> None:
    parser = argparse.ArgumentParser(
        description="Resize images from source into target folder."
    )
    parser.add_argument("source", type=Path)
    parser.add_argument("target", type=Path)
    args = parser.parse_args()
    # Resize images logic here...

The project’s metadata and build configuration:

TOML pyproject.toml
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "image-tools"
version = "0.1.0"
dependencies = ["Pillow"]

[project.scripts]
resize-images = "image_tools.cli:main"

The installation and usage instructions:

Shell
(venv) $ python -m pip install .
(venv) $ resize-images pictures/ thumbnails/

In this version, your project has a well-structured layout, declares its dependencies and metadata explicitly, and exposes a user-friendly command-line interface via an entry point. Users can install it into a virtual environment using standard tools and invoke it just like any other command-line program.

Tutorial

How to Manage Python Projects With pyproject.toml

Learn how to manage Python projects with the pyproject.toml configuration file. In this tutorial, you'll explore key use cases of the pyproject.toml file, including configuring your build, installing your package locally, managing dependencies, and publishing your package to PyPI.

intermediate tools

For additional information on related topics, take a look at the following resources:


By Leodanis Pozo Ramos • Updated Jan. 12, 2026 • Reviewed by Brenda Weleschuk and Bartosz Zaczyński