scikit-build-core: CMake Build Backend for Python
scikit-build-core is a PEP 517 build backend for Python packages with compiled extensions. It drives CMake to build C, C++, and Fortran modules and reads its configuration statically from the [tool.scikit-build] table in pyproject.toml. It is a ground-up rewrite of the classic scikit-build, which wrapped setuptools.
Note
Latest version: 1.0.0 (July 2026). License: Apache-2.0. Backend string: scikit_build_core.build. Requires: Python >=3.8, plus CMake and a C/C++/Fortran toolchain at build time. Maintained under the scikit-build GitHub organization.
When to use scikit-build-core
scikit-build-core fits packages whose build is already expressed in CMake, or whose C, C++, or Fortran sources are too involved for setuptools to compile cleanly. It integrates with the binding libraries these projects rely on: pybind11, nanobind, Cython, SWIG, and Fortran via f2py-cmake.
For Rust extensions, use maturin. For pure-Python packages, use a general backend such as hatchling, flit_core, or uv_build. meson-python is a comparable backend for compiled projects that builds with Meson rather than CMake.
Key Features
- CMake-driven builds: invokes a project’s
CMakeLists.txtto compile C, C++, and Fortran extension modules, fetching CMake (and Ninja) as build requirements when the host lacks them. - Binding-library support: works with pybind11, nanobind, Cython, SWIG, and Fortran (f2py-cmake) for wrapping native code.
- Static configuration: all backend options live under
[tool.scikit-build]inpyproject.toml; no imperative build script is required. - Editable installs: implements PEP 660 editable installs, stabilized in 1.0 with
importlib.resources.files()support, namespace packages, versioned shared-object names, and a manual__loader__.rebuild()for recompiling after source edits. - Dynamic metadata: the
[[tool.dynamic-metadata]]system extracts fields such as the version from external sources at build time, replacing the deprecated[tool.scikit-build.metadata]table. - Reproducible wheels: normalizes timestamps with
SOURCE_DATE_EPOCHto produce bit-for-bit identical builds. - Free-threaded stable ABI: emits
abi3tand combinedabi3.abi3twheel tags for free-threaded builds against the stable ABI.
Configuration
A minimal project declares the backend in [build-system] and its options under [tool.scikit-build]:
[build-system]
requires = ["scikit-build-core"]
build-backend = "scikit_build_core.build"
[project]
name = "example"
version = "0.1.0"
requires-python = ">=3.8"
[tool.scikit-build]
minimum-version = "build-system.requires" # pin behavior to the declared version
cmake.build-type = "Release" # CMake build configurationA CMakeLists.txt alongside pyproject.toml defines the actual build. Other commonly used tables include env for environment-variable defaults with platform overrides, force-include for mapping arbitrary files into the sdist or wheel, and wheel.reproducible for deterministic output.
Scaffolding a project
scikit-build-core init generates a starter project for a chosen binding backend:
uvx scikit-build-core init --backend pybind11 exampleTemplates ship for pybind11, nanobind, C, Cython, SWIG, Fortran, abi3, and abi3t.
Plugins for other backends
scikit-build-core provides plugins that add CMake builds to two other backends: a hatchling plugin (stable as of 1.0) and a setuptools plugin. Both let a project keep its existing backend while delegating the compiled portion to CMake.
Pros
- Native CMake integration reuses an existing
CMakeLists.txtwithout a setuptools shim. - Static
pyproject.tomlconfiguration keeps build metadata declarative. - First-class support for pybind11, nanobind, Cython, SWIG, and Fortran bindings.
- Editable installs, reproducible wheels, and free-threaded stable-ABI tags are built in.
Cons
- Requires CMake and a working C/C++/Fortran toolchain at build time.
- Overkill for pure-Python packages, where a general backend is simpler.
- Does not build Rust extensions; maturin covers that case.
- Producing wheels for many platforms still needs a separate tool such as cibuildwheel.
Learn More
- scikit-build-core documentation
- GitHub repository
- scikit-build-core 1.0 release notes
- Build a Python library with a C++ extension: a tutorial using scikit-build-core with pybind11
- What is a build backend?
- What is PEP 517?
- What is PEP 660?
- cibuildwheel: for building wheels across platforms