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), Windows (AMD64, x86, ARM64), iOS (
arm64_iphoneos,arm64_iphonesimulator,x86_64_iphonesimulator), Android (arm64_v8a,x86_64), and Pyodide for WebAssembly - Mobile builds: iOS support landed in cibuildwheel 3.0 (PEP 730, Tier 3 in Python 3.13) and Android in 3.1 (PEP 738); PyPI accepts both wheel sets
- 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
Mobile Targets
iOS and Android wheels need different runner setups than desktop platforms. iOS builds run on macOS with Xcode and the iOS simulator installed; the simulator is required to run the wheel’s test suite. Android builds run on Linux or macOS with the Android SDK installed. Both targets are invoked the same way as desktop platforms: cibuildwheel --platform ios or --platform android. Wheel selection follows the same build and skip globs that desktop builds use (cp313-android_*, cp313-ios_*, etc.). Briefcase remains the tool for packaging the application; cibuildwheel covers the library wheels the application installs.
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