Configuring a CI service

cibuildwheel works on many popular CI services. Others may work, but it will depend on the software installed on the CI machine/image. See the platforms page for details.

GitHub Actions [linux/mac/windows]

To build Linux, macOS, and Windows wheels using GitHub Actions, create a .github/workflows/build_wheels.yml file in your repo.

Action

For GitHub Actions, cibuildwheel provides an action you can use. This is concise and enables easier auto updating via GitHub's Dependabot; see Automatic updates.

.github/workflows/build_wheels.yml

name: Build

on: [push, pull_request]

jobs:
  build_wheels:
    name: Build wheels on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        # macos-15-intel is an Intel runner, macos-14 is Apple silicon
        os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14]

    steps:
      - uses: actions/checkout@v6
        with:
          persist-credentials: false

      - name: Build wheels
        uses: pypa/cibuildwheel@v3.4.1
        # env:
        #   CIBW_SOME_OPTION: value
        #   ...
        # with:
        #   package-dir: .
        #   output-dir: wheelhouse
        #   config-file: "{package}/pyproject.toml"

      - uses: actions/upload-artifact@v4
        with:
          name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
          path: ./wheelhouse/*.whl

Use env: to pass build options and with: to set package-dir: ., output-dir: wheelhouse and config-file: '' locations (those values are the defaults). You can also pass a comma-separated list of extras to install additional packages. For example, extras: "uv" to install UV into the virtual environment.

pipx

The GitHub Actions runners have pipx installed, so you can easily build in just one line. This is internally how the action works; the main benefit of the action form is easy updates via GitHub's Dependabot.

.github/workflows/build_wheels.yml

name: Build

on: [push, pull_request]

jobs:
  build_wheels:
    name: Build wheels on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        # macos-15-intel is an Intel runner, macos-14 is Apple silicon
        os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14]

    steps:
      - uses: actions/checkout@v6
        with:
          persist-credentials: false

      - name: Build wheels
        run: pipx run cibuildwheel==3.4.1

      - uses: actions/upload-artifact@v4
        with:
          name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
          path: ./wheelhouse/*.whl

Generic

This is the most generic form using setup-python and pip; it looks the most like the other CI examples. If you want to avoid having setup that takes advantage of GitHub Actions features or pipx being preinstalled, this might appeal to you.

.github/workflows/build_wheels.yml

name: Build

on: [push, pull_request]

jobs:
  build_wheels:
    name: Build wheels on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-latest]

    steps:
      - uses: actions/checkout@v6
        with:
          persist-credentials: false

      # Used to host cibuildwheel
      - uses: actions/setup-python@v6

      - name: Install cibuildwheel
        run: python -m pip install cibuildwheel==3.4.1

      - name: Build wheels
        run: python -m cibuildwheel --output-dir wheelhouse
        # to supply options, put them in 'env', like:
        # env:
        #   CIBW_SOME_OPTION: value
        #   ...

      - uses: actions/upload-artifact@v6
        with:
          name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
          path: ./wheelhouse/*.whl

Commit this file, and push to GitHub - either to your default branch, or to a PR branch. The build should start automatically.

For more info on this file, check out the docs.

examples/github-deploy.yml extends this minimal example to include Android, iOS and Pyodide builds, and a demonstration of how to automatically upload the built wheels to PyPI.

Azure Pipelines [linux/mac/windows]

To build Linux, Mac, and Windows wheels on Azure Pipelines, create a azure-pipelines.yml file in your repo.

azure-pipelines.yml

jobs:
- job: linux
  pool: {vmImage: 'ubuntu-latest'}
  steps:
    - task: UsePythonVersion@0
    - bash: |
        set -o errexit
        python3 -m pip install --upgrade pip
        pip3 install cibuildwheel==3.4.1
      displayName: Install dependencies
    - bash: cibuildwheel --output-dir wheelhouse .
      displayName: Build wheels
    - task: PublishBuildArtifacts@1
      inputs: {pathtoPublish: 'wheelhouse'}

- job: macos
  pool: {vmImage: 'macOS-latest'}
  steps:
    - task: UsePythonVersion@0
    - bash: |
        set -o errexit
        python3 -m pip install --upgrade pip
        python3 -m pip install cibuildwheel==3.4.1
      displayName: Install dependencies
    - bash: cibuildwheel --output-dir wheelhouse .
      displayName: Build wheels
    - task: PublishBuildArtifacts@1
      inputs: {pathtoPublish: wheelhouse}

- job: windows
  pool: {vmImage: 'windows-latest'}
  steps:
    - task: UsePythonVersion@0
    - bash: |
        set -o errexit
        python -m pip install --upgrade pip
        pip install cibuildwheel==3.4.1
      displayName: Install dependencies
    - bash: cibuildwheel --output-dir wheelhouse .
      displayName: Build wheels
    - task: PublishBuildArtifacts@1
      inputs: {pathtoPublish: 'wheelhouse'}

Commit this file, enable building of your repo on Azure Pipelines, and push.

Wheels will be stored for you and available through the Pipelines interface. For more info on this file, check out the docs.

CircleCI [linux/mac]

To build Linux and Mac wheels on CircleCI, create a .circleci/config.yml file in your repo,

.circleci/config.yml

version: 2

jobs:
  linux-wheels:
    working_directory: ~/linux-wheels
    docker:
      - image: cimg/python:3.12
    steps:
      - checkout
      - setup_remote_docker
      - run:
          name: Build the Linux wheels.
          command: |
            python3 -m pip install --user cibuildwheel==3.4.1
            cibuildwheel --output-dir wheelhouse
      - store_artifacts:
          path: wheelhouse/

  linux-aarch64-wheels:
    working_directory: ~/linux-aarch64-wheels
    machine:
      image: default
    # resource_class is what tells CircleCI to use an ARM worker for native arm builds
    # https://circleci.com/product/features/resource-classes/
    resource_class: arm.medium
    steps:
      - checkout
      - run:
          name: Build the Linux aarch64 wheels.
          command: |
            python3 -m pip install --user cibuildwheel==3.4.1
            python3 -m cibuildwheel --output-dir wheelhouse
      - store_artifacts:
          path: wheelhouse/

  osx-wheels:
    working_directory: ~/osx-wheels
    macos:
      xcode: 15.4.0
    resource_class: macos.m1.medium.gen1
    steps:
      - checkout
      - run:
          name: Build the OS X wheels.
          command: |
            sudo softwareupdate --install-rosetta --agree-to-license  # for python<=3.8 or x86_64/universal2 tests
            pip3 install cibuildwheel==3.4.1
            cibuildwheel --output-dir wheelhouse
      - store_artifacts:
          path: wheelhouse/

workflows:
  version: 2
  all-tests:
    jobs:
      - linux-wheels
      - linux-aarch64-wheels
      - osx-wheels

Commit this file, enable building of your repo on CircleCI, and push.

Note

CircleCI doesn't enable free macOS containers for open source by default, but you can ask for access. See here for more information.

CircleCI will store the built wheels for you - you can access them from the project console. Check out the CircleCI docs for more info on this config file.

Gitlab CI [linux]

To build Linux wheels on Gitlab CI, create a .gitlab-ci.yml file in your repo,

.gitlab-ci.yml

linux:
  image: python:3.12
  # make a docker daemon available for cibuildwheel to use
  services:
    - name: docker:dind
      entrypoint: ["env", "-u", "DOCKER_HOST"]
      command: ["dockerd-entrypoint.sh"]
  variables:
    DOCKER_HOST: tcp://docker:2375/
    DOCKER_DRIVER: overlay2
    # See https://github.com/docker-library/docker/pull/166
    DOCKER_TLS_CERTDIR: ""
  script:
    - curl -sSL https://get.docker.com/ | sh
    - python -m pip install cibuildwheel==3.4.1
    - cibuildwheel --output-dir wheelhouse
  artifacts:
    paths:
      - wheelhouse/

windows:
  image: mcr.microsoft.com/windows/servercore:1809
  before_script:
    - choco install python -y --allow-downgrade --version 3.12.4
    - choco install git.install -y
    - py -m pip install cibuildwheel==3.4.1
  script:
    - py -m cibuildwheel --output-dir wheelhouse --platform windows
  artifacts:
    paths:
      - wheelhouse/
  tags:
    - saas-windows-medium-amd64

macos:
  image: macos-14-xcode-15
  before_script:
    - python3 -m pip install cibuildwheel==3.4.1
  script:
    - python3 -m cibuildwheel --output-dir wheelhouse
  artifacts:
    paths:
      - wheelhouse/
  tags:
    - saas-macos-medium-m1

Commit this file, and push to Gitlab. The pipeline should start automatically.

Gitlab will store the built wheels for you - you can access them from the Pipelines view. Check out the Gitlab docs for more info on this config file.

⚠️ Got an error? Check the FAQ.

Other CI services

AppVeyor

Appveyor official support was dropped in cibuildwheel v3.0, due to a lack of CI credits. However, it can probably still be used as-is. Check the Appveyor example from the cibuildwheel v2.0 branch: appveyor-minimal.yml.

Cirrus CI [linux/mac/windows]

Due to Cirrus CI end-of-life on June 1, 2026, we no longer officially support this service.

Next steps

Once you've got the wheel building successfully, you might want to set up testing or automatic releases to PyPI.