Skip to content

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.

pyproject.toml
[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-any wheel 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

Learn More

Last updated on

Please submit corrections and feedback...