cibuildwheel Python Wheels: Built for Every CI
cibuildwheel is a PyPA command-line tool that builds and tests Python wheels for macOS, Windows, and Linux inside your CI pipeline. It hands the repair step to auditwheel, delocate, or delvewheel per platform, replacing hand-written build scripts per OS. Reach for it once your package has a C extension and needs wheels for more than one platform; skip it for pure-Python projects, where a plain sdist already does the job.
The Challenge of Cross-Platform Python Wheels
Python package maintainers who ship a C extension can't just run `pip install` and call it done โ every combination of OS, architecture, and CPython/PyPy/GraalPy version needs its own compiled wheel, built inside a container with the right compiler toolchain, then repaired so it doesn't silently depend on a shared library that only exists on the build machine. Before cibuildwheel, that meant hand-writing separate build scripts per CI provider and manually wiring up manylinux containers, delocate, and delvewheel yourself. cibuildwheel's README frames its own reason for existing around exactly that: one command that drives the platform-specific repair tool and target Python matrix for you.
What cibuildwheel Automates
cibuildwheel automates building and testing Python wheels across every platform your package needs to ship for, driven from inside a CI job rather than your laptop. It runs `python -m cibuildwheel --output-dir wheelhouse`, builds against the CPython, PyPy, or GraalPy versions you select, repairs each wheel with auditwheel, delocate, or delvewheel depending on platform, then reinstalls it and runs your test command against it.
Comprehensive Platform and Python Support
- โTargets CPython 3.9 through 3.15, PyPy 3.9-3.11 v7.3, and GraalPy 3.12 v25.0, per the version support table in the README โ PyPy and GraalPy builds are restricted to manylinux wheels.
- โBuilds manylinux and musllinux wheels for x86_64, i686, aarch64, ppc64le, and s390x, plus an armv7l target the README marks experimental (it runs on an Ubuntu-based image since no RHEL-based image exists for that architecture).
- โCovers macOS Intel and Apple Silicon, plus Windows 64-bit, 32-bit, and an experimental Windows ARM64 target built via cross-compilation โ the README notes arm64 can't be tested on Windows CI runners.
- โAlso builds Pyodide (WebAssembly) wheels, and โ starting with CPython 3.13 โ Android and iOS wheels, per the support table.
- โRepairs shared library dependencies per platform: auditwheel on Linux, delocate on macOS, delvewheel on Windows, bundling what each wheel needs so it runs without extra install steps.
- โReinstalls the just-built wheel and runs the project's own test command against it, rather than just checking that the build didn't error.
- โRuns on GitHub Actions, Azure Pipelines, CircleCI, and GitLab CI, with configuration set either in pyproject.toml or as environment variables โ the same config works across providers.
- โOptions cover build selection (platform, archs, enable), build customization (before-build, repair-wheel-command, container-engine), and test control (test-command, test-requires, test-skip), per the options table in the README.
Integrating with Your CI Workflow
The README's example workflow installs a pinned version with `python -m pip install cibuildwheel==4.2.0`, then runs `python -m cibuildwheel --output-dir wheelhouse` as a CI step โ no local install is expected, since cibuildwheel is meant to run inside the CI job itself. The sample `.github/workflows/wheels.yml` in the README builds across a matrix of `ubuntu-latest`, `ubuntu-24.04-arm`, `windows-latest`, `windows-11-arm`, `macos-15-intel`, and `macos-latest` runners, using `actions/setup-python` to host cibuildwheel and `actions/upload-artifact` to collect the built `.whl` files from the `wheelhouse` directory. The README also points to a dedicated GitHub Action and to per-provider setup for Azure Pipelines, CircleCI, and GitLab CI in the full documentation, though it doesn't spell those out inline.
Customizing Your Wheel Builds
Every option can be set in `pyproject.toml` or as an environment variable, which is what the `CIBW_`-prefixed variables in most examples map to. Build selection options like `platform`, `archs`, and `build`/`skip` narrow which wheels actually get built; `enable` turns on extra selector categories such as CPython prereleases. Build customization runs shell commands at defined points โ `before-all` runs once per platform before any wheel builds, `before-build` runs before each individual wheel, and `repair-wheel-command` overrides the default auditwheel/delocate/delvewheel step entirely if you need a custom repair tool. Testing options are separate: `test-command` runs against the installed wheel, `test-requires` and `test-extras` pull in test dependencies, and `test-skip` excludes specific build identifiers from testing, all documented in the options table in the README.
Projects Using cibuildwheel
- โขBuilding wheels with Cython and C++ extensions at scale โ the README names scikit-learn's own cibuildwheel config as 'a complex but clean' example of this.
- โขShipping compiled Python packages for data tooling: the README lists DuckDB, an analytical in-process SQL database, and NumPy as projects using cibuildwheel.
- โขCompiling with mypyc instead of plain Python โ the README names MyPy's own mypyc-compiled wheel builds as an example.
- โขRunning wheel builds on self-hosted runners: the README lists Triton as doing exactly that with cibuildwheel.
- โขBuilding C-extension-heavy libraries like Facebook AI Research's fairseq toolkit and the Prophet forecasting library, both named in the README's working-examples table.
Strengths
- โOne config drives four CI providers โ GitHub Actions, Azure Pipelines, CircleCI, and GitLab CI โ set through the same pyproject.toml options or environment variables, per the README.
- โCovers an unusually wide platform matrix for a single tool: manylinux/musllinux across five architectures, macOS Intel and Apple Silicon, Windows including ARM64, Pyodide, Android, and iOS.
- โHandles the repair step itself โ auditwheel, delocate, or delvewheel โ instead of leaving you to wire each one up by hand per platform.
- โTests the actual built-and-installed wheel, not just a source checkout, catching packaging bugs that unit tests run against the repo wouldn't.
- โBacked by real-world adopters named in the README โ scikit-learn, NumPy, DuckDB, Matplotlib, and MyPy among them โ across a range of build complexities.
- โBSD-2-Clause license, and configuration lives in pyproject.toml alongside the rest of your packaging metadata rather than a separate proprietary format.
Important Considerations and Warnings
- โณWhen wheels are built and tested, arbitrary code originating in your project and its dependencies is executed; the README itself warns that OCI containers and Pyodide offer no security assurances, therefore suggesting that the build job be kept separate from the job uploading to PyPI, and that credentials be handled with care.
- โณThe repaired wheel can bundle dynamically linked libraries from the build machine โ the README's legal note compares this to static linking and says it 'might have some license implications,' so you need to check the licenses of what you're pulling in.
- โณWindows ARM64 support is marked experimental and built via cross-compilation; the README states arm64 can't actually be tested on that CI platform.
- โณmanylinux armv7l support is also experimental โ the README notes there's no RHEL-based container image for that architecture, so it runs on an Ubuntu-based image instead.
- โณGitLab CI's Linux ARM support requires emulation distributed separately from cibuildwheel, and several CI-provider combinations for Android, iOS, and Pyodide builds are flagged in the README's own support table as untested in cibuildwheel's CI even though they may work.
Other Python Wheel Building Tools
Frequently Asked Questions
cibuildwheel runs on GitHub Actions, Azure Pipelines, CircleCI, and GitLab CI, per its README, with the same pyproject.toml or environment-variable configuration working across all four.
cibuildwheel builds wheels for CPython 3.9 through 3.15, PyPy 3.9 through 3.11 (v7.3), and GraalPy 3.12 (v25.0), though PyPy and GraalPy builds are limited to manylinux wheels.
cibuildwheel targets macOS (Intel and Apple Silicon), Windows (64-bit, 32-bit, and experimental ARM64), manylinux/musllinux Linux across five architectures plus experimental armv7l, Pyodide, Android, and iOS.
cibuildwheel's README flags one: since repair tools like delocate, auditwheel, and delvewheel can bundle dynamically linked libraries from the build machine, similar to static linking, you should check the license of any code you're pulling in.
cibuildwheel repairs each wheel with a platform-specific tool โ auditwheel on Linux, delocate on macOS, delvewheel on Windows โ bundling shared library dependencies so the wheel runs without extra install steps.
cibuildwheel installs each built wheel and runs your project's own test command against it, configurable through the test-command, test-requires, and test-skip options in its README.
Who should try it โ and who should skip
Try cibuildwheel if you maintain a Python package with a C, C++, Cython, or Rust extension and need wheels for more than one OS or architecture โ the CI-driven matrix and automatic repair step replace what would otherwise be hand-written build scripts per platform. Skip it if your package is pure Python with no compiled code, since a plain sdist or a single `pip wheel` covers that without any of cibuildwheel's platform matrix or container overhead; it's also not the tool for building a single local wheel on your own machine outside CI.
Related repositories
Curious whether cibuildwheel is right for you?
Let ChatGPT, Claude, or Perplexity look into it โ click below and see what AI actually says about cibuildwheel.
