cibuildwheel: Cross-Platform Python Wheel Builder
cibuildwheel is a CI tool that builds Python wheels for multiple platforms, architectures, and Python versions from a single configuration. It runs on CI servers (GitHub Actions, GitLab CI, Azure Pipelines, CircleCI, and Cirrus CI), automating the work of compiling C/C++/Rust/Cython extensions and producing manylinux/musllinux-compliant wheels.
Note
cibuildwheel is maintained by the Python Packaging Authority (PyPA). It is the standard tool that most open-source projects with compiled extensions use to build and publish platform-specific wheels.
Key Features
- Platform coverage: Builds wheels for Linux (x86_64, aarch64, i686, ppc64le, s390x), macOS (x86_64, arm64, universal2), and Windows (AMD64, x86, ARM64)
- Python version matrix: Supports CPython 3.8 through 3.14, with opt-in support for PyPy, GraalPy, and CPython free-threaded builds
- Automatic shared library bundling: Runs auditwheel on Linux, delocate on macOS, and delvewheel on Windows to bundle dependencies into wheels
- Built-in testing: Installs the built wheel in a clean environment and runs a test command after each build, catching packaging errors before release
- Build backend agnostic: Works with any PEP 517-compliant build backend (setuptools, scikit-build-core, maturin, meson-python, etc.)
- Linux containerization: Runs Linux builds inside OCI containers (Docker or Podman), ensuring reproducible manylinux/musllinux compatibility without modifying the host
Configuration
cibuildwheel reads configuration from pyproject.toml under [tool.cibuildwheel], from environment variables with the CIBW_ prefix, or from CLI flags. Environment variables override pyproject.toml values.
[tool.cibuildwheel]
build = ["cp311-*", "cp312-*", "cp313-*"]
skip = ["*-win32", "*-manylinux_i686"]
test-command = "pytest {package}/tests"
test-requires = ["pytest"]
[tool.cibuildwheel.linux]
before-all = "yum install -y libfoo-devel"
[tool.cibuildwheel.macos]
archs = ["x86_64", "arm64"]Key options:
| Option | Purpose |
|---|---|
build / skip |
Glob patterns selecting which Python version + platform combos to build or skip |
archs |
Target architectures (auto, auto64, native, or specific like x86_64 arm64) |
enable |
Opt-in categories: pypy, graalpy, cpython-prerelease, cpython-freethreading |
build-frontend |
Which tool builds the wheel: build (default), build[uv], pip, or uv |
before-all |
Shell command run once per platform before any builds (install system libraries) |
before-build |
Shell command run before each individual wheel build |
test-command |
Command to run after building each wheel ({package} and {project} are placeholders) |
test-requires |
Packages to install alongside the wheel for testing |
repair-wheel-command |
Override the default auditwheel/delocate/delvewheel command |
environment |
Environment variables set during build and test |
Platform-specific sections ([tool.cibuildwheel.linux], .macos, .windows) override global values for that platform. The [[tool.cibuildwheel.overrides]] array allows per-build overrides matched by glob patterns.
GitHub Actions
The official GitHub Action runs cibuildwheel directly:
- uses: pypa/[email protected]
env:
CIBW_BUILD: "cp312-* cp313-*"A typical workflow uses a matrix strategy with one job per OS, uploads wheel artifacts, and publishes to PyPI on release using trusted publishing.
Pros
- Handles the full OS x architecture x Python version matrix with minimal configuration
- Automatically bundles shared libraries so wheels are self-contained and manylinux-compliant
- Tests each wheel after building, catching missing dependencies or broken linkage before release
- Works with any PEP 517 build backend without modification
- Supports uv as a build frontend for faster builds (
build-frontend = "build[uv]")
Cons
- Build times scale with the size of the platform matrix; a full CPython 3.11-3.14 x Linux/macOS/Windows build can take 30+ minutes of CI time
- Adds complexity that pure-Python packages do not need (use a single
py3-none-anywheel instead) - Bundling shared libraries (via auditwheel/delocate) requires verifying that all bundled library licenses permit redistribution
- ARM Linux builds via QEMU emulation are slow; native ARM runners (available on GitHub Actions as
ubuntu-24.04-arm) are faster but cost more