Skip to content

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.txt to 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] in pyproject.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_EPOCH to produce bit-for-bit identical builds.
  • Free-threaded stable ABI: emits abi3t and combined abi3.abi3t wheel 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]:

pyproject.toml
[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 configuration

A 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 example

Templates 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.txt without a setuptools shim.
  • Static pyproject.toml configuration 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

Last updated on