# setuptools: Python Package Build Backend

Setuptools is the original Python [build backend](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md). Created in 2004 as an extension of [distutils](https://pydevtools.com/handbook/reference/distutils.md), it handles building source distributions ([sdists](https://pydevtools.com/handbook/reference/sdist.md)), [wheels](https://pydevtools.com/handbook/reference/wheel.md), C extensions, and entry points.

## When to use setuptools

Setuptools is the right choice for packages with C extensions, Cython code, or other compiled components that newer backends like hatchling and `uv_build` do not handle. For pure-Python packages without legacy constraints, [hatch](https://pydevtools.com/handbook/reference/hatch.md) or [uv](https://pydevtools.com/handbook/reference/uv.md) provide simpler workflows.

## Key Features

- Builds both sdists and wheels
- Compiles C extensions and Cython code
- Manages console scripts and plugin registration via entry points
- Handles package data files and non-code resources
- Supports custom build steps and commands

## Configuration

Setuptools projects define configuration in [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md). The legacy `setup.py` file is still supported but no longer required.

```toml {filename="pyproject.toml"}
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "example"
version = "0.1.0"
description = "Example package"
requires-python = ">=3.10"
dependencies = ["requests>=2.28.0"]
```

The legacy equivalent uses a `setup.py` script:

```python {filename="setup.py"}
from setuptools import setup

setup(
    name="example",
    version="0.1.0",
    description="Example package",
    python_requires=">=3.10",
    install_requires=["requests>=2.28.0"],
)
```

## Using setuptools with uv

To create a new [uv](https://pydevtools.com/handbook/reference/uv.md) project that uses setuptools as its build backend:

```bash
uv init --build-backend setuptools my-lib
```

To build distributions:

```bash
uv build
```

Both `uv build` and `python -m build` invoke setuptools when pyproject.toml declares `setuptools.build_meta` in the `[build-system]` table.

## Pros

- Handles complex packaging scenarios including C extensions and custom build steps
- Compatible with modern Python packaging standards ([PEP 621](https://pydevtools.com/handbook/explanation/what-is-pep-621-compatibility.md))
- Decades of development with broad platform support

## Cons

- Legacy API carries historical design choices that can be confusing
- No built-in dependency locking; requires additional tools for [lockfiles](https://pydevtools.com/handbook/explanation/what-is-a-lock-file.md)
- More configuration options than newer backends, creating a steeper learning curve

## Learn More

- [How to migrate from setup.py to pyproject.toml](https://pydevtools.com/handbook/how-to/migrate-setup-py.md)
- [What is a build backend?](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md)
- [distutils](https://pydevtools.com/handbook/reference/distutils.md)
- [Should I run `python setup.py`?](https://pydevtools.com/handbook/explanation/should-i-run-python-setuppy-commands.md)
- [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md)
- [Setuptools documentation](https://setuptools.pypa.io/en/latest/)
- [Setuptools pyproject.toml configuration](https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html)
- [Setuptools with pyproject.toml example](https://github.com/python-developer-tooling-handbook/demo-setuptools-without-setuppy)
- [Setuptools with setup.py example](https://github.com/python-developer-tooling-handbook/demo-setuptools-with-setuppy)
