build vs Other Tools¶
The Python packaging ecosystem has several tools that work together. This guide helps you understand when to use build versus other tools.
When to use build¶
Use build when you want to:
Create distribution packages (source distributions and/or wheels) for your project
Build for your current Python version and platform only
Create packages to upload to PyPI
Test that your package builds correctly
Build as part of a development workflow
Build is a build frontend - it knows how to invoke build backends (setuptools, hatchling, flit, etc.) but doesn’t handle testing, multi-version builds, or task automation.
$ python -m build
This builds your package for the currently active Python interpreter.
When to use cibuildwheel¶
Use cibuildwheel when you need to build wheels for multiple Python versions and platforms:
Building wheels for distribution on PyPI
Supporting Python 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
Supporting multiple operating systems (Linux, macOS, Windows)
Building manylinux/musllinux wheels (standardized Linux wheel formats)
Building wheels with compiled extensions (C, C++, Rust, etc.)
cibuildwheel uses build under the hood but handles all the complexity of:
Running builds in manylinux containers
Testing wheels after building
Handling platform-specific quirks
Proper ABI tagging
Example .github/workflows/build.yml:
name: Build
on: [push, pull_request]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: pypa/cibuildwheel@v2.17
- uses: actions/upload-artifact@v4
with:
name: wheels
path: ./wheelhouse/*.whl
See cibuildwheel documentation for complete details.
When to use tox¶
Use tox when you need to:
Test your package across multiple Python versions (e.g., 3.9, 3.10, 3.11)
Run tests in isolated environments
Automate testing workflows
Run linters (code checkers), formatters, type checkers
Build documentation
Orchestrate multiple development tasks
Example tox.toml:
[env_run_base]
description = "run test suite with {basepython}"
deps = [
"pytest",
"pytest-cov",
]
commands = [
["pytest", "tests"],
]
[env.build]
description = "build the package"
deps = ["build"]
commands = [["python", "-m", "build"]]
[env.lint]
description = "run linters and type checkers"
deps = [
"ruff",
"mypy",
]
commands = [
["ruff", "check", "."],
["mypy", "src"],
]
Tox can call build to create distributions, but its main purpose is test automation.
See tox documentation for complete details.
When to use nox¶
Use nox when you want tox-like functionality but prefer Python over INI:
Example noxfile.py:
import nox
@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12"])
def tests(session):
session.install("pytest", "pytest-cov")
session.run("pytest", "tests")
@nox.session
def build(session):
session.install("build")
session.run("python", "-m", "build")
See nox documentation for complete details.
When to use uv¶
Use uv when you want:
Fast package installation (faster than pip)
Workspace management (monorepos with multiple packages)
Combined dependency resolution and installation
Modern Python packaging workflows
uv can also build packages:
$ uv build
This is equivalent to python -m build --installer=uv.
See uv documentation for complete details.
When to use pip¶
Use pip when you need to:
Install packages (not build them)
Install from PyPI or other indexes
Install in editable mode for development
Manage dependencies in your environment
pip can build packages as a side effect of installation, but for explicit building, use build.
# Installing (use pip)
$ pip install mypackage
# Installing in editable mode (use pip)
$ pip install -e .
# Building distributions (use build)
$ python -m build
How they work together¶
A typical complete workflow might use all these tools:
Development workflow¶
# Install your package in editable mode
$ pip install -e .[dev]
# Run tests across Python versions
$ tox
# Build distributions
$ python -m build
# Upload to PyPI
$ twine upload dist/*
CI/CD workflow¶
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- run: pip install tox
- run: tox -e py
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hynek/build-and-inspect-python-package@v2
build_wheels:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: pypa/cibuildwheel@v2.17
This workflow:
Uses tox to test across Python versions
Uses build (via hynek’s action) to create sdist
Uses cibuildwheel to create wheels for all platforms
Decision tree¶
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#4051b5','primaryTextColor':'#fff','primaryBorderColor':'#2c3e8f','lineColor':'#5468c4','secondaryColor':'#7c8fd6','tertiaryColor':'#e8eaf6'}}}%%
flowchart TD
A[What do you need to do?] --> B{Build a package?}
B -->|Yes| C{For how many platforms?}
B -->|No, just testing| D{Multiple Python versions?}
B -->|No, just installing| E[Use pip or uv]
C -->|Current platform only| F[Use python -m build]
C -->|Multiple platforms/versions| G[Use cibuildwheel]
D -->|Yes| H[Use tox or nox]
D -->|No| I[Use pytest or your test runner]
style F fill:#4051b5,stroke:#2c3e8f,color:#fff
style G fill:#4051b5,stroke:#2c3e8f,color:#fff
style H fill:#7c8fd6,stroke:#5468c4,color:#fff
style I fill:#7c8fd6,stroke:#5468c4,color:#fff
style E fill:#f57c00,stroke:#e65100,color:#fff
Quick reference¶
Tool |
Purpose |
Use for |
|---|---|---|
build |
Build sdist/wheel for one Python |
Creating distributions |
cibuildwheel |
Build wheels for all platforms |
Distributing on PyPI |
tox |
Test across Python versions |
CI/testing automation |
nox |
Like tox, but Python-based |
CI/testing automation |
uv |
Fast package manager |
Installing + optional building |
pip |
Package installer |
Installing packages |
twine |
Upload to PyPI |
Publishing |
See also¶
Basic Usage for build command examples
CI/CD Integration for CI/CD integration
Build Backends to understand build vs backend