# cibuildwheel: Cross-Platform Python Wheel Builder


cibuildwheel is a CI tool that builds Python [wheels](https://pydevtools.com/handbook/reference/wheel.md) 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](https://peps.python.org/pep-0600/)/musllinux-compliant wheels.

> [!NOTE]
> cibuildwheel is maintained by the [Python Packaging Authority (PyPA)](https://pydevtools.com/handbook/explanation/what-is-pypa.md). 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](https://peps.python.org/pep-0730/), Tier 3 in Python 3.13) and Android in 3.1 ([PEP 738](https://peps.python.org/pep-0738/)); 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](https://github.com/pypa/auditwheel) on Linux, [delocate](https://github.com/matthew-brett/delocate) on macOS, and [delvewheel](https://github.com/adang1345/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](https://pydevtools.com/handbook/explanation/what-is-pep-517.md)-compliant [build backend](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md) ([setuptools](https://pydevtools.com/handbook/reference/setuptools.md), 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](https://pydevtools.com/handbook/reference/briefcase.md) 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.

```toml {filename="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:

```yaml
- uses: pypa/cibuildwheel@v3.4
  env:
    CIBW_BUILD: "cp312-* cp313-*"
```

A typical workflow uses a matrix strategy with one job per OS, uploads wheel artifacts, and publishes to [PyPI](https://pydevtools.com/handbook/explanation/what-is-pypi.md) on release using [trusted publishing](https://pydevtools.com/handbook/how-to/how-to-publish-to-pypi-with-trusted-publishing.md).

## 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](https://pydevtools.com/handbook/reference/uv.md) 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

- [cibuildwheel documentation](https://cibuildwheel.pypa.io/)
- [GitHub repository](https://github.com/pypa/cibuildwheel)
- [What is a wheel?](https://pydevtools.com/handbook/reference/wheel.md)
- [What is an sdist?](https://pydevtools.com/handbook/reference/sdist.md)
- [What is a build backend?](https://pydevtools.com/handbook/explanation/what-is-a-build-backend.md)
- [How to publish to PyPI with trusted publishing](https://pydevtools.com/handbook/how-to/how-to-publish-to-pypi-with-trusted-publishing.md)
- [How to build multi-platform wheels with cibuildwheel](https://pydevtools.com/handbook/how-to/how-to-build-multi-platform-wheels-with-cibuildwheel.md)
