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), 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.

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