nanobind: tiny and efficient C++/Python bindings
nanobind is a C++17-first binding library designed for creating efficient and minimalistic C++/Python interoperability layers. It enables seamless exposure of C++ types and functions to Python, often with significantly faster compile times, smaller binaries, and lower runtime overhead compared to alternatives like pybind11 and Cython. The library is actively developed, with a focus on performance and modern C++ practices, and supports Python 3.9+ and PyPy 7.3.10+.
Warnings
- breaking nanobind has a separate ABI version that is not subject to semantic versioning. Upgrades to nanobind (e.g., from 2.1 to 2.2) can introduce ABI incompatibilities, requiring all downstream packages that use nanobind to be rebuilt. This is critical for projects relying on pre-built binary wheels from other nanobind-dependent libraries.
- breaking Support for Python 3.8 was officially dropped with nanobind version 2.10.0, which was released in December 2025. Projects using older Python versions must either upgrade their Python environment or pin nanobind to a version prior to 2.10.0.
- breaking In nanobind 2.0.0, the `nb::enum_<T>()` binding declaration changed to create `enum.Enum` or `enum.IntEnum`-derived types. Code that previously cast enum entries directly to integers might break if the enum is not `enum.IntEnum`-derived. Accessing `my_enum_entry.value` is the recommended approach.
- gotcha Warnings about 'leaked instances/functions/types' can occur, often indicating underlying reference counting issues within the binding code. This can be exacerbated by Python type annotations or improper `Py_INCREF` usage, leading to resource leaks during interpreter finalization.
- gotcha Conflicting type bindings can arise if multiple nanobind-based extensions expose or interact with the same C++ types (e.g., `std::latch`) inconsistently. nanobind will warn about such conflicts (e.g., `RuntimeWarning: nanobind: type 'latch' was already registered!`), which can lead to unpredictable behavior or crashes.
Install
-
pip install nanobind -
conda install -c conda-forge nanobind
Imports
- nanobind
import your_nanobind_module
Quickstart
# Assuming you have built a nanobind extension named 'my_ext'
# For example, with C++ code like:
# NB_MODULE(my_ext_impl, m) { m.def("hello", []() { return "Hello world!"; }); }
# And an __init__.py with: from ._my_ext_impl import hello
import my_ext
message = my_ext.hello()
print(message)