Changelog

nanobind uses a semantic versioning policy for its API. There is also a separate ABI version that is not subject to semantic versioning. Please review the ABI compatibility documentation for details.

Version 3.1.0 (TBA)

  • The low-level instance API gained nb::inst_python_derived(), which reports whether a nanobind instance belongs to a Python subclass of the bound type. Previous versions provided this function under an internal name.

  • The functions nb::keep_alive_obj() and nb::keep_alive_cb() expose the mechanism behind the nb::keep_alive annotation. The first keeps a Python object alive until another one expires, and the second invokes a callback at that point. Both were previously only reachable through internal interfaces.

Version 3.0.1 (Aug 28, 2026)

  • Fixed an issue where the std::chrono::duration caster interpreted a Python float even when implicit conversion was not desired. (PR #1420).

  • Minor tweak to the NB_SLOT_ALIAS macro so that clang-cl can compile nanobind 3.0.0 code on Windows. This compiler is now also tested by the CI. (PR #1421).

  • Fixed two problems in the constexpr logic that processes function annotations. Bindings could cause OOB writes by declaring an incorrect number of nb::arg annotations. A nullary method with an implicit self annotation failed to compile. (PR #1419).

  • Reverted a change from version 2.13.0 (PR #1334), where the stub generator stripped the prefix of the enclosing class and wrote the short name of a nested class. PyRight/mypy handle the qualified form, and need it to avoid ambiguities. (PR #1422).

  • The package metadata now declares requires-python = ">=3.10" so that installers do not pick up an incompatible version. (Issue #1424, PR #1425).

Version 3.0.0 (Aug 22, 2026)

This major release of nanobind introduces split mode to address a frustration shared by many extension developers. It also includes minor API breaks discussed below, though most existing code is expected to require no adaptations.

  • Split mode: nanobind introduces a new distribution model named split mode. It fixes the wheel distribution problem, where binary wheels have to be built for a vast matrix of Python versions and platforms. Python’s stable ABI exists to fix this problem but falls short in several ways:

    • Python’s stable ABI makes nanobind slower. Performance-critical code like nanobind’s function dispatcher needs access to Python internals to work efficiently, and such low-level access is prohibited by the stable ABI.

    • Meaningfully reducing the wheel count only works when targeting a low stable ABI version. The earliest version usable by nanobind was 3.12, which means that users still have to ship separate wheels for Python 3.10 and 3.11.

    • A Python 3.12 stable ABI floor would leave nanobind “forever frozen” at the stagnant 3.12 feature set, which lacks many important features and improvements shipped since then.

    Split mode gets rid of all of these problems by splitting a nanobind extension into a frontend and a backend part. The backend contains the advanced and performance-critical parts that benefit from coupling to a specific Python version. It is tiny and shipped on PyPI for relevant platforms and Python versions, so users do not have to worry about it (though it is possible for them to also ship their own backend).

    The frontend part (i.e., your code) delegates most work to the backend and targets the Python 3.10 stable ABI, so that it can be distributed as a single Python wheel per platform that covers every supported Python version.

    Split mode is an optional feature, and the traditional workflow without it remains the default. To enable split mode, pass the BACKEND_MODULE option to nanobind_add_module(), naming the backend module that your extension should use.

    nanobind_add_module(
        my_ext
        my_ext.cpp
        BACKEND_MODULE nanobind_backend
    )
    

This release also brings a set of performance improvements, mainly to the wrapper API (i.e., the bindings of Python within C++):

  • Interned string keys: Idiomatic code like

    nb::object value = obj.attr("name");
    dict["name"] = value;
    

    used to generate many temporary str objects, whose construction is surprisingly expensive. nanobind now constructs and memoizes interned Python strings in an internal cache so that repeat use of a string literal becomes fast. Interned strings further take a fast path in Python’s attribute and dictionary lookup.

    With this change, a keyword attribute lookup (obj.attr("name")) reduces from 30ns to 9ns on my machine. The change affects nb::getattr(), nb::setattr(), nb::delattr(), nb::hasattr(), the attr() and operator[]() accessors, nb::dict::get(), the contains() methods of nb::dict, nb::set, nb::frozenset, and nb::mapping, and the keyword argument names of nb::arg().

  • Unnecessary reference counting: the C++ wrappers performed many unnecessary calls to Py_INCREF() and Py_DECREF() that have a nontrivial cost. The overhead of performing a Python function call, looking up an attribute or dictionary entry from C++ dropped significantly (~1.3-1.4x depending on the operation).

  • Faster iteration: ranges exposed through nb::make_iterator() previously raised a C++ exception to signal the end of each loop. The cost of the resulting stack unwinding (several microseconds) could easily dominate iteration over small sequences. The generated __next__ function now signals exhaustion without raising a C++ exception, which reduces the cost of a loop over a 4-element sequence from 5167ns to 125ns on my machine. The per-element cost is unchanged.

  • Faster sequence construction: creating and filling sequences iteratively using code like

    nb::list out;
    for (size_t i = 0; i < n; ++i)
        out.append(/* value of entry i */);
    

    is expensive in the limited ABI, which also affects the new split mode. The necessary per-iteration Python library calls and underlying internal checks can add up to significant overheads.

    nanobind 3 addresses this issue using the new nb::tuple_builder and nb::list_builder classes. They provide a fast path for constructing tuples and lists of a known size. Use them as follows:

    nb::list_builder builder(n);
    for (size_t i = 0; i < n; ++i)
        builder.put(/* value of entry i */);
    nb::list result = builder.commit();
    

    All internal sequence casters now use this form. Building sequences becomes up to ~1.5x faster when using this approach in split-mode extensions.

  • Faster sequence traversal: The nb::{tuple,list}::{begin,end}() iterators were redesigned and now have nearly the same performance in unstable ABI and stable/split mode builds. (Previously, there was a ~2.5x overhead when traversing large sequences in stable ABI extensions.)

  • Thread-safe container bindings: the nb::bind_vector() and nb::bind_map() container bindings now lock the container in free-threaded builds, which makes their concurrent use safe. This safety guarantee also extends to list iterators, and key/value/item views of maps. Similarly to the Python dict, map bindings raise a RuntimeError when they detect concurrent modification during iteration.

  • Bindings can now conclude with .freeze() to make the type immutable on Python 3.15 and newer:

    nb::class_<A>(m, "A")
        .def(...)
        .freeze();
    

    This renders the type object immutable, and subsequent attempts to modify it from Python or C++ raise an exception. A neat side effect of freezing a type is that it accelerates constructor dispatch by 7-10% on Python 3.15, since it allows Python’s adaptive specializing interpreter to generate faster bytecode.

    The ability to freeze types was already introduced in CPython 3.14, but it is disadvantageous there due to a bug that actually reduces performance. Therefore, nanobind only honors the .freeze() request on CPython 3.15+.

Bindings also became more robust at interpreter shutdown:

  • Interpreter finalization: code that enters Python from a non-Python thread can hang indefinitely when the interpreter begins to shut down. This can be a tricky problem in C++ codebases, where destructors may want to communicate a cleanup event to Python, without knowing whether it is still safe to do so.

    PEP 788 adopts an official API where code can request a kind of critical section that either fails or keeps the interpreter alive until release. The nb::gil_scoped_acquire API now builds on this feature when running on Python 3.15 or newer.

    Many existing internal uses of this pattern moved to the new API, including the deleters of std::shared_ptr and std::unique_ptr, the wrapper around a Python callable held in a std::function, ndarray deallocation and nb::python_error. They simply skip their work instead of hanging when Python can no longer be used. Function calls to trampoline also detect this situation and defer to the C++ base instead of the Python override, or raise when the method is pure virtual.

    API break: nb::gil_scoped_acquire can now fail when the interpreter is no longer usable. Code that may run in this situation must guard subsequent use of the Python API using the .is_valid() method.

    nb::gil_scoped_acquire guard;
    if (guard.is_valid())
        Py_DECREF(o);
    

    Older interpreters keep their previous behavior, where is_valid() always reports success. Split-mode extensions pick up the improved handling from a backend upgrade without recompiling.

    The rewrite also removed an inefficiency of the former implementation. On Python 3.12+, a thread that already holds a thread state can now proceed directly, which saves an acquire/release pair and reduces the cost of a trampoline dispatch from 8.7ns to 5.7ns on my machine.

The release makes several further API-breaking changes that unlock internal improvements:

  • Trampolines: nanobind 3 switches to a new trampoline mechanism to override C++ methods in Python. Instead of caching data about such overrides within instances (which costs 16 bytes per overload), the cache is now located within type objects. Trampoline dispatch became faster, and its cost no longer grows with the number of overridable methods. Monkey-patching methods into an existing type object now works correctly and invalidates this cache.

    API break: it is no longer necessary to specify the Size of the trampoline in the NB_TRAMPOLINE(Base, Size) macro, and doing so will cause a deprecation warning.

    struct PyDog : Dog {
        NB_TRAMPOLINE(Dog, 1); // deprecated, warns
        ...
    

    Rewrite it as follows:

    struct PyDog : Dog {
        NB_TRAMPOLINE(Dog); // OK
        ...
    

    In the past, it was possible to monkey-patch methods into instances:

    inst = Dog()
    inst.bark = ...  # Ignored since nanobind 3.0.0
    

    Such assignments are now ignored by the trampoline. Methods can only be overridden in the type, either at creation time, or by patching it later:

    # Override in a subclass
    class MyDog(Dog):
        def bark(self): ...
    
    # .. or monkey-patch
    inst = Dog()
    Dog.bark = ...
    
  • Return value policies: policies like nb::rv_policy::move used to be enum values and now became compile-time tags. As a consequence, function bindings like

    m.def("f", &f, nb::rv_policy::reference);
    

    can specialize to the policy and generate more efficient code.

    API break: Bindings with “computed” policies are no longer legal:

    auto policy = ...;
    m.def("f", &f, policy); // <-- not allowed, policy must be a compile-time tag
    
  • Argument annotations: Argument binding annotations like

    m.def("f", &f, "x"_a.noconvert() = nb::none());
    

    are now handled at compile time. As a consequence, function bindings can specialize and generate more efficient code.

    API break: Bindings with “computed” annotations are no longer legal:

    bool is_noconvert = ..;
    m.def("f", &f, "x"_a.noconvert(is_noconvert));
    

    Argument default values remain runtime parameters. However, whether a parameter accepts None is detected at compile time.

    // OK: nanobind can infer that 'x' is nullable
    m.def("f", &f, "x"_a = nb::none());
    
    // OK: nanobind can infer that 'x' is nullable
    nb::object none_value = nb::none();
    m.def("f", &f, "x"_a.none() = none_value);
    
    // Bad: nanobind cannot infer at compile time that 'x' should be nullable
    m.def("f", &f, "x"_a = none_value);
    
  • The None wrapper type: nb::none used to be a function returning an nb::object. It is now a wrapper class whose default constructor nb::none() references the None singleton.

    API break: a conditional expression can no longer mix nb::none() with a different wrapper type, since the two branches have unrelated types:

    // Bad: the branches of the conditional have unrelated types
    nb::object doc = cond ? nb::str(value) : nb::none();
    
    // OK
    nb::object doc = cond ? (nb::object) nb::str(value) : (nb::object) nb::none();
    
  • Type caster interface: the flags parameter of the from_python() function in type casters widened from uint8_t to uint32_t:

    bool from_python(nb::handle src, uint32_t flags,
                     nb::detail::cleanup_list *cleanup) noexcept;
    

    Type casters written for nanobind 2.x still compile and behave correctly because the value converts implicitly, though this may cause compiler warnings. It is advisable that you widen the parameter in your casters.

  • Miscellaneous:

    • Python version requirement: nanobind now requires Python 3.10 or newer. Python 3.9 reached its end of life in October 2025, and dropping it removes a number of workarounds for missing C API functionality.

    • The self argument of a method is no longer subject to implicit conversion when the method is called in unbound form (MyClass.method(obj)). This previously worked, which was arguably a bug.

    • nb::mapping::contains() now raises when the underlying lookup fails on Python versions before 3.13 instead of returning false, matching its behavior on 3.13 and newer.

    • The low-level instance functions nb::inst_copy() and nb::inst_move() now detect at runtime whether the target holds a live value and then apply the replace semantics of nb::inst_replace_copy() and nb::inst_replace_move(), which are now aliases.

    • Added the low-level functions nb::type_dict() and nb::type_lookup(), which expose the namespace dictionary of a type object and perform a raw lookup along its method resolution order.

    • Added nb::inst_dict(h), which returns the instance dictionary and provides a more efficient alternative to the expression h.attr("__dict__").

    • The nb::ndarray_traits<T> interface was removed following its deprecation in nanobind 2.2.0. The alternative nb::detail::dtype_traits<T> is documented in the section on nonstandard arithmetic types.

    • stubgen now honors a __nb_signature__ string on the type of a data member and emits it in place of the inferred declaration. See the section on per-member signature overrides for details.

  • Internal ABI version 22.

Note: The 3.0.0 release was yanked since it mistakenly still declared Python 3.9 compatibility. It is supserseded by the 3.0.1 patch release, which also includes several bugfixes.

Version 2.15.0 (Aug 15, 2026)

Most changes in this release revolve around stub generation.

  • The stubgen machinery for generating import statements was rewritten to fix brittleness and prevent it from generating import declarations that were invalid Python syntax. It now records whether a module is imported out of convenience or because it should be re-exported, and it writes self-imports in absolute form. Standard library modules are identified via sys.stdlib_module_names, which changes how imports are grouped and ordered. Parsing and escaping of type and docstring text was made more robust in several places. (commits 8df192, ab446f, 39af7b, 9a7d3d).

  • Stubs for nb::ndarray arguments besides NumPy are now valid Python. They previously carried extra information in square brackets, as in mlx.core.array[dtype=float32, shape=(2, 4)], which tools like ruff and ty reject. (PR #1409).

  • stubgen now accepts multiple pattern files via -p, and the PATTERN_FILE parameter of the CMake nanobind_add_stub() command accepts a list. (commit 581adb).

  • When a pattern file modifies an overload chain with one \doc marker per overload, each marker now expands to the docstring of the associated overload. (commit 5031de).

  • Annotations that name a module through an alias now resolve to the real module name. For example, f(x: np.ndarray) is rendered as f(x: numpy.ndarray). When processing files with from __future__ import annotations, stubgen previously generated incorrect output like import np. (commit 23051a).

  • Properties with a setter but no getter are rendered as a plain annotated attribute. Previous versions emitted a @property decorator without an accompanying function definition. (commit ab446f).

  • stubgen now sets the environment variable NB_STUBGEN to "1". Extensions can query this variable to skip initialization steps that are expensive or inappropriate for stub generation (see the section on detecting stub generation for details). (commit ee6516).

The release also includes minor fixes and improvements not related to stubs. (PR #1406, commits 922a5c, 62b78c, 53d546, ef993f).

  • Internal ABI version 21.

Version 2.14.0 (Aug 7, 2026)

  • Implicit conversion to integer-typed arguments now requires that the input implement Python’s __index__ protocol, which is reserved for lossless integer conversion. The previous implementation explicitly rejected Python float arguments, but mistakenly accepted (and truncated) floating point types that are not float subclasses, such as np.float32. It also accepted strings like "123". Both are considered bugs, hence this change lands in a minor release despite being observable from Python. Arguments such as bool, enum.IntEnum, and NumPy integer scalars continue to convert as before. (commits d33465, a29b10).

  • The type casters for STL sets, maps, and enumerations now check whether an input is convertible up front instead of raising and immediately discarding a Python exception. Since overload resolution routinely probes casters with non-matching arguments, this removes exception overhead from a hot path. (commit 6d130f).

  • nanobind now ships a workaround for spurious leak reports caused by an issue in the typing module. It also fixes an issue where references to internal types were leaked, which generated warnings in valgrind. (commits acd95d, 31618e).

  • Stubgen: read-only static properties are now annotated as Final[T] and read-write ones as ClassVar[T]. ClassVar[Final[T]] is no longer generated. Overriding a read-only static property in a subclass now also works. (commit 4a8f4f).

  • Miscellaneous minor fixes and improvements. (PRs #1389, #1390, #1392, #1394, commits 450d2e, 341ac4).

Version 2.13.0 (Jun 18, 2026)

This release bundles a large set of performance improvements on nanobind’s critical paths. It makes object construction 1.42×-3.2× faster, accelerates function dispatch 1.2×-1.5× and accelerates exchange of ndarrays by up to 2.4×. The release also hardens nanobind against error conditions, and fixes race conditions in free-threaded Python builds.

  • Performance improvements:

    • Added the nb::pooled() class binding annotation, which maintains a per-type pool of instances to accelerate workloads that create large numbers of short-lived objects. Released objects are stashed in the pool and cheaply recycled, skipping allocation, instance registration, and locking (on free-threaded builds). A microbenchmark exercising object construction runs between 1.42× (regular Python) to 3.2× (free-threading with contention) faster. (PR #1366, commit 962cdf).

    • A new “medium” function dispatcher accelerates calls to functions whose arguments are merely named or carry default values (and that use neither nb::args/nb::kwargs nor more than 8 arguments). Such functions previously fell back to the fully general dispatcher. Positional calls to them now run roughly 32% faster, nearly matching positional-only functions. (PR #1370).

    • A specialized fast path now accelerates simple two-argument calls such as binary operators and copy constructors. (PR #1362).

    • A careful tuning pass on the critical path of function calls and object construction led to speedups ranging from 6.2% on regular builds to 16.4% on stable ABI builds. (PR #1374, with a further immortal-type optimization in commit 82f0ce).

    • Optimized the nb::ndarray import and export critical path. Returning an array becomes up to ~58% faster, and consuming one up to ~21% faster. (PR #1375). Separately, improved __dlpack__() keyword parsing speeds numpy.from_dlpack() by a further ~8% (PR #1373).

    • Optimized the nb::ndarray import and export critical path. Returning an array becomes up to ~58% faster, and consuming one up to ~21% faster. (PR #1375). Separately, improved __dlpack__() keyword parsing speeds numpy.from_dlpack() by a further ~8% (PR #1373).

    • nb::ndarray argument detection now probes for the __dlpack__ method and buffer protocol without raising and catching a Python exception, which greatly speeds up rejecting non-array inputs during overload resolution. (PR #1385).

    • Reduced the cost of thread-local storage (TLS) accesses, which are needed by performance-critical nanobind functions in free-threaded builds. In a function calling microbenchmark, the relative cost spent on TLS lookups drops from about 2.8% to about 0.3%. (PR #1365).

    • Added a specialized nb::dict accessor that provides more efficient read, write, and delete operations on dictionaries. (commit 033754).

    • Free-threaded builds now skip reference counting operations on type, enumeration, and function objects known to be immortal. (PRs #1367, #1368).

    • nb::supplement<T> data is now stored outside of the Python type object, which simplifies and accelerates a performance-critical function that checks if a type is a nanobind type. (PR #1364).

    • repr() of nb::bind_vector / nb::bind_map containers is now linear rather than quadratic in the output size. (commit e9f3c4).

    • Hot-path accesses of well-known attributes (__name__, __qualname__, __new__, etc.) now use pre-interned strings instead of constructing a temporary key string on each call. (commit c048c2).

    • Error handling in nb_type_get() and the layout of nb_inst were reorganized to improve code generation. (PRs #1363, #1369).

    • The CMake build system now disables the GCC/Clang stack protector for libnanobind release builds. It previously already did this for compiled extensions, but forgot to forward the flag to the libnanobind component. The stack protector imposes significant object size (~9-12%) and performance (~1-2%) overheads in extensions in exchange for a highly dubious security improvement. As before, users can opt out by passing PROTECT_STACK to nanobind_add_module(). Stack protection is now also disabled on MSVC builds. (PR #1374).

  • A systematic, AI-assisted safety audit (PR #1371) hardened nanobind against many latent crashes, undefined behavior, memory leaks, and free-threading data races. Most have no practical trigger in ordinary single-threaded code but matter for robustness, unusual inputs, and free-threaded builds:

    • Fixed numerous crashes, aborts, and instances of undefined behavior: deleting a static property (commit bcca09), a constructor receiving self as a keyword argument (commit 95cf4c), nb::eval/nb::exec with the default scope (commit 81ebfe), overload errors mentioning un-encodable keyword names (commit ba937e), python_error::what() on non-UTF-8 traceback paths (commit 2d1497), type_get_slot() on static types (commit 840a29), constructing out-of-range flag enumerations (commit 1f2e7c), an uninitialized read in the enum caster (commit 87e2f2), a memory-corrupting nb::implicitly_convertible() enum target (commit 8c8404), a one-byte out-of-bounds read in buffer-format parsing (commit d66eae), out-of-memory paths in inst_new_ext/keep_alive (commit 22437a), and missing validation in nb_type_name()/nb_type_from_metaclass() (commits 7f6ad0, facc51).

    • Fixed several use-after-free and dangling-reference bugs in the type casters: the std::pair/std::tuple casters over generic sequences (commit 3de121), the std::set caster over iterables yielding fresh objects (commit 714242), implicit conversion to a std::shared_ptr parameter (commit 227306), self-aliasing extend/update on nb::bind_vector/nb::bind_map containers (commit 7c9799), and a dangling key in .attr(handle) / operator[](handle) accessors (commit b993cd).

    • Fixed several memory leaks: STL container constructors and the nb::bind_vector slice getter that fail mid-conversion (commits 141125, a983b1), accessor in-place operators (commit a3a83c), the framework module during nb::ndarray export (commit 13e51f), and reference cycles routed through bound methods, which were not tracked by the cyclic garbage collector (commit 6ed390).

    • Fixed several free-threading data races and synchronization bugs: nb::list iteration (commit ae765f) and accessor caching (commit 069f06), exception-translator registration (commit 89cfee), the enable_shared_from_this path of the std::shared_ptr caster (commit e14b33), a critical section outliving its GIL release in the trampoline (commit c656e9), a type reference-count leak for Python subclasses (commit 4ba3ed), a stale iterator in enum_create() (commit 2ba750), reference-count manipulation without the GIL on a diagnostic path (commit 983dcd), a non-atomic update in intrusive_counter::set_self_py (commit ee64aa), and lock accounting for arguments that are both locked and carry a default value (commit 945654).

    • The nb::ndarray exporter now honors the copy and dl_device arguments to __dlpack__() (commit 28040d), honors buffer-protocol request flags such as PyBUF_WRITABLE and PyBUF_STRIDES (commit 10da85), refuses to export ownerless arrays whose framework cannot copy them rather than aliasing freed memory (commit 8d3e87), and safely handles a missing or non-string __module__ while detecting the source framework (commit 0a5851).

    • Fixed several defects in the Eigen casters: a deep copy and potential process abort when returning a sparse matrix by value (commit 824546), incorrect flag handling in the sparse-matrix casters (commit 69e4fa), an invalid inner stride for empty dynamic-stride Map/Ref arguments (commit db3ac6), and a null cleanup-list dereference in the reference_internal casters (commit c747fb).

    • Avoided acquiring the GIL during cleanup that runs after interpreter shutdown, which previously aborted at exit when a std::function, unique_ptr deleter, or nb::ndarray outlived the interpreter (commits ab2d8b, 2fce88, 71aa65).

    • Corrected several smaller behaviors. A failing nb::cast<T>() now raises nb::cast_error instead of silently re-dispatching or reporting a confusing error (commit d3c027). The nb::dict::get() accessor is now reference-safe on free-threaded builds and no longer swallows errors from unhashable keys (commit 9e9958). An nb::int_ or nb::slice constructed from a char now yields an integer rather than a one-character string (commit 7f2b14). Self-aliasing slice assignment v[::-1] = v now matches Python list semantics (commit 99dfbe). The single-argument dispatcher fast path now applies nb::rv_policy::reference_internal consistently with the other arities (commit 9c8927). The stable-ABI seq_get* helpers now clear the error indicator on item-copy failure (commit 5eb2cf). Error paths no longer run arbitrary Python under the internals lock (commit 85edf8). The PyErr_WarnFormat call sites now handle warnings-as-errors (commit 1c9cf5). Finally, the per-extension static_pyobjects cache is rebuilt after a domain is torn down and re-imported (commit 64ceeb).

  • Stub generation improvements:

    • Docstrings repeated across a function’s overloads are now emitted only once, on the last overload. (issue #1357, PR #1381).

    • classmethod and staticmethod members are now correctly recognized, producing exact signatures instead of generic *args, **kwargs stubs. (PR #1302).

    • Static properties are now wrapped into ClassVar[...] and Final[...]. (PR #1303).

    • Types from typing_extensions are now imported using from-style imports, consistent with the treatment of typing and collections.abc. (PR #1305).

    • Fixed a name prefixing issue. (PR #1153).

    • Default values for typing.TypeVar and typing.TypeVarTuple are now emitted. (PR #1318).

    • References to a nested type from within its enclosing class body now use the short, resolvable name instead of the fully-qualified one. (PR #1334, commit 12c3e6).

    • The pattern-application counter is now incremented correctly, so applied patterns no longer produce spurious “no matches found” warnings. (PR #1348).

    • Pattern files may now use a new \import directive to import a whole module (with an optional as alias), for cases where a type hint introduced by a pattern is the only use of that module. (PR #1347).

  • nb::init<...> now constructs instances using direct-initialization (parentheses) instead of list-initialization (braces). The previous behavior could spuriously select a constructor taking std::initializer_list over the intended overload. Aggregates without a matching constructor continue to use list-initialization. (issue #1074, PR #1377).

  • Added nb::DRef1 and nb::DMap1, Eigen Ref/Map variants with a compile-time unit inner stride that can improve auto-vectorization of Eigen code. (issue #1263, PR #1378).

  • nb::ndarray can now return arrays to Apple’s MLX array framework via the new nb::mlx framework annotation. (PR #1386).

  • Miscellaneous minor fixes and improvements. (PRs #1301, #1304, #1307, #1312, #1325, #1327, #1356, #1351, #1379, commits b238ff, 2deac9, e33dee, b22f1f, 96cc36, 279947, bc6bf8, 3408c6, 7c9e94, ef1266, 0528ff).

  • Internal ABI version 20.

Version 2.12.0 (Feb 25, 2026)

  • Added nb::memoryview that wraps the Python memoryview type. (PR #1291).

  • Made stub generation compatible with the Realtime Sanitizer (RTSan) from Clang 20. (PR #1285).

  • Fixed a use-after-free when calling functions after their module has been deleted. The internals state is now reference-counted with references held by modules, functions, and types. This also fixes memory leaks reported in issue #957. (PR #1287).

  • Fixed two regressions from v2.11.0 related to the implicit std::optional .none() annotation: an off-by-one error that applied the annotation to the wrong argument for methods, and a missing convert flag that silently disabled implicit type conversions. (issues #1281, #1293, commits ed7ab3, 1f9627).

  • Internal ABI version 19.

Version 2.11.0 (Jan 29, 2026)

  • This release improves binding performance using CPython’s adaptive specializing interpreter (PEP 659). The speedups are automatic and require no changes to binding code:

    Operation

    Speedup

    Requirements

    Method calls

    1.22x faster

    Python 3.11+

    Static attribute lookups

    1.63x faster

    Python 3.14+

    This was achieved by making a number of nanobind-internal classes (nb_func, nb_method, nb_meta, etc.) immutable, which allows CPython to specialize generic LOAD_ATTR opcodes to faster type-specific versions (LOAD_ATTR_METHOD for method calls, LOAD_ATTR_CLASS for static attribute lookups). (PR #1257).

  • Added the nb::never_destruct class binding annotation to inform nanobind that it should not bind the destructor. (PR #1251, commit 4ba51f).

  • Argument annotations for std::optional<T>-typed arguments now implicitly have the .none() annotation applied (i.e., no need to additionally specify nb::arg("..").none()). (PR #1262, commit 425ca1).

  • Removed a redundant hash table type, reducing the size of libnanobind by 2.5KiB. (commit 4d53cd).

  • Added Python 3.12-3.14 symbols to linker scripts. (commit 36d4a6).

  • Fixed a bug where call_guard could cause an extra copy of the return value. (PR #1249).

  • Don’t link nb_ft.cpp in non-free-threaded builds to avoid linker warnings about empty compilation units. (PR #1271).

  • Internal ABI version 18.

  • Eigen type caster improvements:

    • Fixed conversion of size-zero vectors to Eigen::Map/Eigen::Ref on NumPy 2.4. (PR #1268).

    • Fixed move construction of dense Eigen arrays. (commit cb9075).

  • Stub generation improvements:

    • Fixed O(n²) string concatenation performance issue. (PR #1275).

    • Fixed enumerations with entries named name or value. (issue #1246).

    • Stubgen now preserves module-level docstrings. (commit 8771be).

    • Extended the skip list by two additional enum attributes. (PR #1255).

Version 2.10.2 (Dec 10, 2025)

  • Fixes a regression that broke compilation on 32-bit architectures. (PR #1239).

Version 2.10.1 (Dec 8, 2025)

  • Nanobind now officially supports the MinGW-w64 and Intel ICX compilers. (PR #1188).

  • Version 2.10 drops support for Python 3.8, which reached End-Of-Life in October 2025. (PR #1236).

  • The new nb::array_api framework tag can be used to create an nd-array wrapper object that supports both the Python buffer protocol and the DLPack methods __dlpack__ and __dlpack_device__.

    Furthermore, nanobind now supports importing/exporting tensors via the legacy (unversioned) DLPack interface, as well a new versioned interface. The latter provides a flag indicating whether an nd-array is read-only. (PR #1175).

  • Added bfloat to the nd-array import conversion code, fixing imports of bfloat16 tensors. (PR #1228).

  • nanobind now uses per-module precomputed constants, particularly strings, to avoid costs from creating these repeatedly. This improves the performance of nd-array and enumeration casts. (PR #1184).

  • Fixed a segfault in garbage collection traversal of Python subclasses of class bindings with nb::is_weak_referenceable. (PR #1206).

  • Fixed a potential reference leak in the std::array type caster. (commit bfacaf).

  • STL type casters now directly reject incorrectly sized inputs, which avoids performance pitfalls when passing large arrays. (commit edf575, dc35d6).

  • Fixed __new__ overloads with variadic positional arguments but no variadic keyword arguments, which incorrectly prevented nullary calls. (PR #1172).

  • Removed zero-length arrays to improve compiler compatibility. (PR #1158).

  • Fixed a data race related caused by writes to a bit-field in free-threaded extension builds (PR #1191)

  • Internal ABI version 17.

  • Stub generation improvements:

    • Added a new --exclude-values flag that forces all values to be rendered as ... in stub files. (PR #1185).

    • Added support for typing.ParamSpec in generated stubs. (PR #1194).

    • NumPy boolean arrays now use np.bool_ dtype in generated stubs instead of deprecated alternatives. (commit 20fab9).

    • Auto-generated enum APIs are now excluded from stub files. (PR #1182).

    • Pattern files now support __prefix__ and __suffix__ patterns within classes for further customization of class stubs. (PR #1235).

    • Various minor improvements to the stub generator. (PR #1179).

  • Fixed a regression in 2.10.0 (yanked release) related to handling of the NB_USE_SUBMODULE_DEPS flag that could cause CMake build system failures (commit 06aaa3).

  • Minor/miscellaneous fixes: PRs #1157, #1186, #1193, #1198, #1212, #1218, #1223, #1225, commit cf289b.

Version 2.10.0 (Dec 8, 2025)

This release was yanked due to a regression.

Version 2.9.2 (Sep 4, 2025)

This is a patch release to fix an issue in the new recursive stub generation feature:

  • When creating stubs for a module, the generator must decide whether to store declarations locally (e.g., in foo.pyi) or in a subdirectory (e.g., in foo/__init__.pyi). The latter is necessary, e.g., when foo contains submodules. However, the implemented submodule test was far too conservative and interpreted any imported module (e.g. import os) as a submodule. The patch release fixes this. (commit a65e1b).

Version 2.9.1 (Sep 4, 2025)

This is a patch release to fix a regression in the CMake build system:

  • nanobind 2.9.0 internally adopted the CMake command cmake_path() to normalize paths. This was done for cosmetic reasons, since it improves the readability of generated commands. However, cmake_path() is only available on CMake 3.20+, while nanobind officially supports CMake 3.15+. Version 2.9.1 removes the full path normalization. (commit f703fd).

Version 2.9.0 (Sep 4, 2025)

  • Nanobind’s CMake stub generation command nanobind_add_stub() can now automatically traverse submodule hierarchies and generate many stub files at once. (PR #1148).

  • Recursive stub generation now correctly organizes stub files hierarchically (e.g. my_ext.pyi versus my_ext/__init__.pyi). (commits ad9d3f, 620c1c).

  • The stub generator now exposes NumPy array types as NDArray[np.float32] (or similar) instead of Annotated[ArrayLike, dict(...)] to simplify type-checking. (PR #1149, commit 37dd2c).

  • Nanobind (finally!) correctly implements in-place updates to dicts, lists, etc. Previously, a C++ operation like

    nb::dict my_dict = ...;
    my_dict["key"] += 1;
    

    performed an addition but failed to reassign the updated value to the original key. (PR #1119).

  • When cast operations like nb::cast() fail to convert a value, they previously raised a generic std::bad_cast exception that loses the context of why the cast failed. When a Python error status is available, they now preferentially raise nb::python_error. This helps to track down issues with default argument conversion. (PR #1137).

  • Miscellaneous minor fixes and improvements. (PRs #1092, #1107, #1120, #1124. #1128, #1135, #1138, #1142, commits d99b3f, 014790).

  • Minor documentation tweaks. (PRs #1109, #1108, #1114, #1117, #1134, #1132, #1090).

Version 2.8.0 (July 16, 2025)

  • Added nb::fallback wrapper type, which is a nb::handle that always requires implicit conversion during casting. This is convenient when adding catch-all overloads that must handle arbitrary Python objects, without interfering with implicit conversion of arguments in other overloads.

  • The nanobind::literals namespace now includes _s to create a Python string from source code literals. (PR #1051).

  • Added the convenience methods nb::dict::empty(), nb::list::empty(), nb::set::empty(), and nb::tuple::empty(). (PR #1052)

  • Added a nb::dict::get() function to perform dictionary lookups with a fallback value in case of failures. (commit d38284).

  • Nanobind now uses multi-phase (as opposed to single-phase) initialization API when registering modules. However, multi-interpreter extensions remain unsupported. (PR #1059).

  • Added nb::frozenset that wraps the Python frozenset type. (PR #1068)

  • Miscellaneous fixes and improvements (commits d4b245, 667451, 62fc99, 8497f7).

Version 2.7.0 (Apr 18, 2025)

  • nanobind now provides a zero-copy type caster for Eigen::Map<Eigen::SparseMatrix>. (PRs #1003, #782).

  • Made handling of return value policies in Eigen type casters more consistent with the rest of nanobind. (Issue #971, commit 5cdf58).

  • The Eigen sparse matrix caster now correctly handles scipy.sparse objects with unsorted indices. (PR #981).

  • Nanobind’s CMake stub generation command nanobind_add_stub() now detects when an extension uses sanitizers (TSAN, ASAN, UBSAN). It then injects the sanitizer library into the Python process ahead of time so that the extension can be loaded. Previously, stub generation failed in such cases. (PR #1000).

  • The entries of stub files are now sorted in their original definition order. Previously, they were alphabetically sorted, which caused issues with external tooling. (PR #938).

  • Fixed detection and handling of imports and types in external modules in stubgen that could lead to incorrect declarations in some cases. (PRs #939, #940).

  • The stub generator now detects method aliases and preserves this information instead of duplicating the definition. (PR #735).

  • Corrected a flaw in the recommended implementation of tp_traverse in garbage-collected bindings. (PRs #1015).

  • Added support for binding functions that accept a std::variant<...> that is not default-constructible (because its first alternative isn’t). (PR #987).

  • Added support for casting const-qualified std::unique_ptr<T> values. (PR #988).

  • nb::typed<T, ...> now supports construction from T, making it more ergonomic to return values with type annotations. (PR #1012

  • Miscellaneous fixes and improvements (PRs #1014, #1005, #1004, #990, #997, commits f2b08c, eef931, f1b2f5, dbdb60, 2c83fb, 87de84).

Version 2.6.1 (Mar 28, 2025)

  • nanobind assigns an ABI tag to compiled extensions and uses it to isolate incompatible extensions from each other. This tag was unnecessarily fine-grained, often causing isolation where an actual ABI compatibility was not present. This release updates the tagging scheme to address this long-standing inconvenience. (PR #778).

  • Added specialized function dispatchers to accelerate calls to 0 and 1-argument functions. (PR #944).

  • Improved the efficiency of nb::getattr(obj, key, default) in cases where obj[key] does not exist. (commit bb05f5).

  • Internal ABI version 16.

  • Miscellaneous fixes and improvements (PRs #913, #914, #916, #931, #978, commit 1595d2).

Version 2.6.0 (Mar 28, 2025)

  • This release was yanked due to a regression.

Version 2.5.0 (Feb 2, 2025)

  • Added nb::def_visitor<..>, which can be used to define your own binding logic that operates on a nb::class_<..> when an instance of the visitor object is passed to class_::def(). This generalizes the mechanism used by init, new_, etc, so that you can create binding abstractions that “feel like” the built-in ones. (PR #884)

  • Added some special forms for nb::typed<T, Ts...> (PR #835):

    • nb::typed<nb::object, T> or nb::typed<nb::handle, T> produces a parameter or return value that will be described like T in function signatures but accepts any Python object at runtime.

    • nb::typed<nb::callable, R(Args...)> produces a Python callable signature Callable[[Args...], R]; similarly, nb::typed<nb::callable, R(...)> (with a literal ellipsis) produces the Python Callable[..., R].

  • It is now possible to create Python subclasses of C++ classes that define their constructor bindings using nb::new_(). Previously, attempting to instantiate such a Python subclass would instead produce an instance of the base C++ type. Note that it is still not possible to override virtual methods in such a Python subclass, because the object returned by the new_() constructor will generally not be an instance of the alias/trampoline type. (PR #859)

  • Fixed the nb::int_ constructor so that it casts to an integer when invoked with a floating point argument.

  • Multi-level inheritance (e.g., A B C) previously did not work on Python 3.12+ when a base class (e.g., A) provided a trampoline implementation. This is now fixed. (commit 92d9cb).

  • A new NB_SUPPRESS_WARNINGS parameter of nanobind_add_module() that marks the nanobind and Python include directories as SYSTEM include directories, which suppresses any potential warning messages originating there. This is mainly of relevance for projects that artificially raise the warning level using flags like -pedantic, -Wcast-qual, -Wsign-conversion. (PR #868).

  • Fixed (benign) reference leaks that could occur when std::shared_ptr<T> instances were still alive at interpreter shutdown time. (commit fb8157).

  • The floating-point type caster now only performs value-changing narrowing conversions during the implicit conversion phase. They can be entirely avoided by passing the .noconvert() argument annotation. (PR #829)

  • The std::complex type caster now only performs value-changing narrowing conversions during the implicit conversion phase. They can be entirely avoided by passing the .noconvert() argument annotation. Also, during the implicit conversion phase, if the Python object is not a complex number object but has a __complex__() method, it will be called. (PR #854)

  • Fixed an overly strict check that could cause a function taking an nb::ndarray<...> to refuse specific types of column-major input without implicit conversion. (PR #847, commit b95eb7).

Fixes for free-threaded builds

  • Fixed a race condition in free-threaded extensions that could occur when nb::make_iterator was concurrently used by multiple threads. (PR #832).

  • Fixed a race condition in free-threaded extensions that could occur when multiple threads access the Python object associated with the same C++ instance, which does not exist yet and therefore must be created. (issue #867, PR #887).

  • Removed double-checked locking patterns in accesses to internal data structures to ensure correct free-threaded behavior on architectures with weak memory ordering such as ARM (PR #819).

Version 2.4.0 (Dec 6, 2024)

  • Added a function annotation nb::call_policy<Policy>() which supports custom function wrapping logic, calling Policy::precall() before the bound function and Policy::postcall() after. This is a low-level interface intended for advanced users. The precall and postcall hooks are able to observe the Python objects forming the function arguments and return value, and the precall hook can change the arguments. See the linked documentation for more details, important caveats, and an example policy. (PR #767)

  • nb::make_iterator now accepts its iterator arguments by value, rather than by forwarding reference, in order to eliminate the hazard of storing a dangling C++ iterator reference in the returned Python iterator object. (PR #788)

  • The std::variant type_caster now does two passes when converting from Python. The first pass is done without implicit conversions. This fixes an issue where std::variant<U, T> might cast a Python object wrapping a T to a U if there is an implicit conversion available from T to U. (issue #769)

  • Restored support for constructing types with an overloaded __new__ that takes no arguments, which regressed with the constructor vector call acceleration that was added in nanobind 2.2.0. (issue #786)

  • Bindings for augmented assignment operators (as generated, for example, by .def(nb::self += nb::self)) now return the same object in Python in the typical case where the C++ operator returns a reference to *this. Previously, after a += b, a would be replaced with a copy. (PR #803)

  • Added an overload to nb::isinstance which tests if a Python object is an instance of a Python class. This is in addition to the existing overload, which tests if a Python object is an instance of a bound C++ class. (PR #805).

  • Added support for overriding static properties, such as those defined using def_prop_ro_static, in subclasses. Previously this would fail with an error. (PR #806).

  • Other minor fixes and improvements. (PRs #771, #772, #748, and #753)

Version 2.3.0

There is no version 2.3.0 due to a deployment mishap.

  • Added casters for Eigen::Map<Eigen::SparseMatrix<...>> types from the Eigen library. (PR #782).

Version 2.2.0 (October 3, 2024)

  • nanobind can now target free-threaded Python, which replaces the Global Interpreter Lock (GIL) with a fine-grained locking scheme (see PEP 703) to better leverage multi-core parallelism. A separate documentation page explains this in detail (PRs #695, #720)

  • nanobind has always used PEP 590 vector calls to efficiently dispatch calls to function and method bindings, but it lacked the ability to do so for constructors (e.g., MyType(arg1, arg2, ...)).

    Version 2.2.0 adds this missing part, which accelerates object construction by up to a factor of 2×. The difference is especially pronounced when passing keyword arguments to constructors. Note that this improvement only applies to Python version 3.9 and newer (PR #706, commits e24d7f, 0acecb, 77f910, 2c96d5).

  • A new nb::is_flag() annotation in nb::enum_<T>() produces enumeration bindings deriving from enum.Flag, which enables bit-wise combination using compatible operators (&, |, ^, and ~). Further combining the annotation with nb::is_arithmetic() creates enumerations deriving from enum.IntFlag. (PRs #599, #688, #688, #727, #732)

  • A refactor of nb::ndarray<...> was an opportunity to realize three usability improvements:

    1. The constructor used to return new nd-arrays from C++ now considers all template arguments:

      Previously, only the framework and data type annotations were taken into account when returning nd-arrays, while all of them were examined when accepting arrays during overload resolution. This inconsistency was a repeated source of confusion among users.

      To give an example, the following now works out of the box without the need to redundantly specify the shape and strides to the Array constructor below:

      using Array = nb::ndarray<float, nb::numpy, nb::shape<4, 4>, nb::f_contig>;
      
      struct Matrix4f {
          float m[4][4];
          Array data() { return Array(m); }
      };
      
      nb::class_<Matrix4f>(m, "Matrix4f")
          .def("data", &Matrix4f::data, nb::rv_policy::reference_internal);
      
    2. A new nd-array .cast() method forces the immediate creation of a Python object with the specified target framework and return value policy, while preserving the type signature in return values. This is useful to return temporaries (e.g. stack-allocated memory) from functions.

    3. Added a new and more general mechanism nanobind::detail::dtype_traits<T> to declare custom ndarray data types like float16 or bfloat16. The old interface (nanobind::ndarray_traits<T>) still exists but is deprecated and will be removed in the next major release. See the documentation for details.

    There are two minor but potentially breaking changes:

    1. The nd-array type caster now interprets the nb::rv_policy::automatic_reference return value policy analogously to the nb::rv_policy::automatic, which means that it references a memory region when the user specifies an owner, and it otherwise copies. This makes it safe to use the nb::cast() and nb::ndarray::cast() functions that use this policy as a default.

    2. The nb::any_contig memory order annotation, which previously did nothing, now accepts C- or F-contiguous arrays and rejects non-contiguous ones.

    For further details on the nd-array changes, see PR #721, For further details on the nd-array changes, see PR #742, and commit 4647ef.

  • The NVIDIA CUDA compiler (nvcc) is now explicitly supported and included in nanobind’s CI test suite (PR #710).

Version 2.1.0 (Aug 11, 2024)

  • Temporary workaround for a internal compiler error in version 17.10 of the MSVC compiler. This workaround will be removed once fixed versions are deployed on GitHub actions. (issue #613, commit f2438b).

  • nanobind no longer prevents casting to a C++ container of pointers T* where T is a type with a user-defined type caster if the caster seems to operate by extracting a T* from the Python object rather than a T. This change was prompted by discussion #605.

  • Switched nanobind wheel generation from setuptools to scikit-build-core (PR #618).

  • Improved handling of const-ness in nb::ndarray (PR #491).

  • Keyword argument annotations are now properly supported with nb::new_, passed in the same way they would be with nb::init. (issue #668)

  • Ability to use nb::cast to create object with the nb::rv_policy::reference_internal return value policy (PR #667).

  • Enable char type caster to produce '\0' (PR #661).

  • Added .def_static() member to nb::enum_, which had been lost in a redesign of the enumeration implementation in nanobind version 2.0.0. (commit 38990e).

  • Fixes for two minor sources of memory leaks (PR #595, #647).

  • The nd-array wrapper nb::ndarray now properly handles CuPy arrays (#594).

  • Added nb::hash(), a wrapper for the Python hash() function (commit 01fafa).

  • Various minor stubgen fixes (PRs #667, #658, #632, #620, #592).

Version 2.0.0 (May 23, 2024)

The 2.0.0 release of nanobind is entirely dedicated to types [1]! The project has always advertised seamless Python ↔ C++ interoperability, and this release tries to bring a similar level of interoperability to static type checkers like MyPy, PyRight, PyType, and editors with interactive autocompletion like Visual Studio Code, PyCharm, and many other LSP-compatible IDEs.

This required work on three fronts:

  1. Stub generation: the above tools all analyze Python code statically without running it. Because the import mechanism of compiled extensions depends the Python interpreter, these tools weren’t able to inspect the contents of nanobind-based extensions.

    The usual solution involves writing stubs that expose the module contents to static analysis tools. However, writing stubs by hand is tedious and error-prone.

    This release adds tooling to automatically extract stubs from existing extensions. The process is fully integrated into the CMake-based build system and explained in a new documentation section.

  2. Better default annotations: once stubs were available, this revealed the next problem: the default nanobind-provided function and class signatures were too rudimentary, and this led to a user poor experience.

    The release therefore improves many builtin type caster so that they produce more accurate type signatures. For example, the STL std::vector<T> caster now renders as collections.abc.Sequence[T] in stubs when it is used as an input, and list[T] when it is used as part of a return value. The nb::make_*_iterator() family of functions return typed iterators, etc.

  3. Advanced customization: a subset of the type signatures in larger binding projects will generally require further customization. The features listed below aim to enable precisely this:

    • In Python, many built-in types are generic and can be parameterized (e.g., list[int]). The nb::typed<T, Ts...> wrapper enables such parameterization within C++ (for example, the int-specialized list would be written as nb::typed<nb::list, int>). Read more.

    • The opposite is also possible: passing nb::is_generic() to the class binding constructor

      nb::class_<MyType>(m, "MyType", nb::is_generic())
      

      produces a generic type that can be parameterized in Python (e.g. MyType[int]). Read more.

    • The nb::sig annotation overrides the signature of a function or method, e.g.:

      m.def("f", &f, nb::sig("def f(x: Foo = Foo(0)) -> None"), "docstring");
      

      Each binding of an overloaded function can be customized separately. This feature can be used to add decorators or control how default arguments are rendered. Read more.

    • The nb::sig annotation can also override class signatures in generated stubs. Stubs often take certain liberties in deviating somewhat from the precise type signature of the underlying implementation. For example, the following annotation adds an abstract base class advertising that the class implements a typed iterator.

      using IntVec = std::vector<int>;
      
      nb::class_<IntVec>(m, "IntVec",
                         nb::sig("class IntVec(collections.abc.Iterable[int])"));
      

      Nanobind can’t subclass Python types, hence this declaration is technically untrue. On the flipside, such a declaration can assist static checkers and improve auto-completion in visual IDEs. This is fine since these tools only perform a static analysis and never import the actual extension. Read more.

    • The nb::for_setter and nb::for_getter annotations enable passing function binding annotations (e.g., signature overrides) specifically to the setter or the getter part of a property.

    • The nb::arg("name") argument annotation (and "name"_a shorthand) now have a .sig("signature") member to control how a default value is rendered in the stubs and docstrings. This provides more targeted control compared to overriding the entire function signature.

    • Finally, nanobind’s stub generator supports pattern files containing custom stub replacement rules. This catch-all solution addresses the needs of advanced binding projects, for which the above list of features may still not be sufficient.

Most importantly, it was possible to support these improvements with minimal changes to the core parts of nanobind.

These release breaks API and ABI compatibility, requiring a new major version according to SemVer. The following changes are noteworthy:

  • The nb::enum_<T>() binding declaration is now a wrapper that creates either a enum.Enum or enum.IntEnum-derived type. Previously, nanobind relied on a custom enumeration base class that was a frequent source of friction for users.

    This change may break code that casts entries to integers, which now only works for arithmetic (enum.IntEnum-derived) enumerations. Replace int(my_enum_entry) with my_enum_entry.value to work around the issue.

  • The nb::bind_vector<T>() and nb::bind_map<T>() interfaces were found to be severely flawed since element access (__getitem__) created views into the internal state of the STL type that were not stable across subsequent modifications.

    This could lead to unexpected changes to array elements and undefined behavior when the underlying storage was reallocated (i.e., use-after-free).

    nanobind 2.0.0 improves these types so that they are safe to use, but this means that element access must now copy by default, potentially making them less convenient. The documentation of nb::bind_vector<T>() discusses the issue at length and presents alternative solutions.

  • The functions nb::make_iterator(), nb::make_value_iterator() and nb::make_key_iterator() suffer from the same issue as nb::bind_vector() explained above.

    nanobind 2.0.0 improves these operations so that they are safe to use, but this means that iterator access must now copy by default, potentially making them less convenient. The documentation of nb::make_iterator() discusses the issue and presents alternative solutions.

  • The nb::raw_doc annotation was found to be too inflexible and was removed in this version.

  • The nb::typed wrapper listed above actually already existed in previous nanobind versions but was awkward to use, as it required the user to provide a custom type formatter. This release makes the interface more convenient.

  • The nb::any placeholder to specify an unconstrained nb::ndarray axis was removed. This name was given to a new wrapper type nb::any indicating typing.Any-typed values.

    All use of nb::any in existing code must be replaced with -1 (for example, nb::shape<3, nb::any, 4>nb::shape<3, -1, 4>).

  • Keyword-only arguments are now supported, and can be indicated using the new nb::kw_only() function annotation. (PR #448).

  • nanobind classes now permit overriding __new__, in order to support C++ singletons, caches, and other types that expose factory functions rather than ordinary constructors. Read the section on customizing Python object creation for more details. (PR #473).

  • When binding methods on a class T, nanobind will now produce a Python function that expects a self argument of type T. Previously, it would use the type of the member pointer to determine the Python function signature, which could be a base of T, which would create problems if nanobind did not know about that base. (PR #471).

  • nanobind can now handle keyword arguments that are not interned, which avoids spurious TypeError exceptions in constructs like fn(**pickle.loads(...)). The speed of normal function calls (which generally do have interned keyword arguments) should be unaffected. (PR #469).

  • The owner=nb::handle() default value of the nb::ndarray constructor was removed since it was bug-prone. You now have to specify the owner explicitly. The previous default (nb::handle()) continues to be a valid argument.

  • There have been some changes to the API for type casters in order to avoid undefined behavior in certain cases. (PR #549).

    • Type casters that implement custom cast operators must now define a member function template can_cast<T>(), which returns false if operator cast_t<T>() would raise an exception and true otherwise. can_cast<T>() will be called only after a successful call to from_python(), and might not be called at all if the caller of operator cast_t<T>() can cope with a raised exception. (Users of the NB_TYPE_CASTER() convenience macro need not worry about this; it produces cast operators that never raise exceptions, and therefore provides a can_cast<T>() that always returns true.)

    • Many type casters for container types (std::vector<T>, std::optional<T>, etc) implement their from_python() methods by delegating to another, “inner” type caster (T in these examples) that is allocated on the stack inside from_python(). Container casters implemented in this way should make two changes in order to take advantage of the new safety features:

      • Wrap your flags (received as an argument of the outer caster’s from_python method) in flags_for_local_caster<T>() before passing them to inner_caster.from_python(). This allows nanobind to prevent some casts that would produce dangling pointers or references.

      • If inner_caster.from_python() succeeds, then also verify inner_caster.template can_cast<T>() before you execute inner_caster.operator cast_t<T>(). A failure of can_cast() should be treated the same as a failure of from_python(). This avoids the possibility of an exception being raised through the noexcept load_python() method, which would crash the interpreter.

    The previous cast_flags::none_disallowed flag has been removed; it existed to avoid one particular source of exceptions from a cast operator, but can_cast<T>() now handles that problem more generally.

  • Internal ABI version 14.

Footnote

Version 1.9.2 (Feb 23, 2024)

  • Nanobind instances can now be made weak-referenceable by specifying the nb::is_weak_referenceable tag in the nb::class_<..> constructor. (PR #335, commits fc7709, 3562f6).

  • Added a nb::bool_ wrapper type. (PR #382, commit 90dfba).

  • Ensure that the GIL is held when releasing nb::ndarray. (issue #377, commit a958e8).

  • nb::try_cast() no longer crashes the interpreter when attempting to cast a Python None to a C++ type that was bound using nb::class_<...>. Previously this would raise an exception from the cast operator, which would result in a call to std::terminate() because try_cast() is declared noexcept. (PR #386).

  • Fixed memory corruption in a PyPy-specific code path in nb::module_::def_submodule() (commit 21eaff).

  • Don’t implicitly convert complex to non-complex nd-arrays. (issue #364, commit ea2569).

  • Support for non-assignable types in the std::optional<T> type caster (PR #358, commit 0c9b64).

  • nanobind no longer assumes that docstrings provided to function binding (of type const char *) have an infinite lifetime and it makes copy. (issue #393, commit b3b6f4).

  • Don’t pass compiler flags if they may be unsupported by the used compiler. This gets NVCC to work out of the box (that said, this change does not elevate NVCC to being an officially supported compiler). (issue #383, commit a307ea).

  • Added a CMake install target to the nanobind build system. (PR #356, commit 5bde65, commit 978dbb, commit f5d8de).

  • Internal ABI version 13.

  • Minor fixes and improvements.

Version 1.9.0-1.9.1 (Feb 18, 2024)

Releases withdrawn because of a regression. The associated changes are listed above in the 1.9.2 release notes.

Version 1.8.0 (Nov 2, 2023)

  • nanobind now considers two C++ std::type_info instances to be equal when their mangled names match. The previously used pointer comparison was fast but fragile and often caused multi-part extensions to not recognize each other’s types. This version introduces a two-level caching scheme (search by pointer, then by name) to fix such problems once and for all, while avoiding the cost of constantly comparing very long mangled names. (commit b515b1).

  • Fixed casting of complex-valued constant nb::ndarray<T> instances. (PR #338, commit ba8c7f).

  • Added a type caster for std::nullopt_t (PR #350).

  • Added the missing C++ → Python portion of the type caster for Eigen::Ref<..> (PR #334).

  • Minor fixes and improvements.

  • Internal ABI version 12.

Version 1.7.0 (Oct 19, 2023)

New features

  • The nd-array class nb::ndarray<T> now supports complex-valued T (e.g., std::complex<double>). For this, the header file nanobind/stl/complex.h must be included. (PR #319, commit 6cbd13).

  • Added the function nb::del(), which takes an arbitrary accessor object as input and tries to delete the associated entry. The C++ statement

    nb::del(o[key]);
    

    is equivalent to del o[key] in Python. (commit 4dd745).

  • Exposed several convenience functions for raising exceptions as public API: nb::raise, nb::raise_type_error, and nb::raise_python_error. (commit 0b7f3b).

  • Added nb::globals(). (PR #311, commit f0a9eb).

  • The char* type caster now accepts nullptr and converts it into a Python None object. (PR #318, commit 30a6ba).

  • Added the function nb::is_alive(), which returns false when nanobind was destructed by Python (e.g., during interpreter shutdown) making further use of the API illegal. (commit b431d0).

  • Minor fixes and improvements.

  • Internal ABI version 11.

Bugfixes

  • The behavior of the nb::keep_alive<Nurse, Patient> function binding annotation was changed as follows: when the function call requires the implicit conversion of an argument, the lifetime constraint now applies to the newly produced argument instead of the original object. The change was rolled into a minor release since the former behavior is arguably undesirable and dangerous. (commit 9d4b2e).

  • STL type casters previously raised an exception when casting a Python container containing a None element into a C++ container that was not able to represent nullptr (e.g., std::vector<T> instead of std::vector<T*>). However, this exception was raised in a context where exceptions were not allowed, causing the process to be abort()-ed, which is very bad. This issue is now fixed, and such conversions are refused. (PR #318, commits d1ad3b and 5f25ae).

  • The STL sequence casters (std::vector<T>, etc.) now refuse to unpack str and bytes objects analogous to pybind11. (commit 7e4a88).

Version 1.6.2 (Oct 3, 2023)

  • Added a missing include file used by the new intrusive reference counting sample implementation from v1.6.0. (commit 31d115).

Version 1.6.1 (Oct 2, 2023)

  • Added missing namespace declaration to the ref intrusive reference counting RAII helper class added in version 1.6.0. (commit 3ba352).

Version 1.6.0 (Oct 2, 2023)

New features

Bugfixes

  • Fixed a serious issue involving combinations of bound types (e.g., T) and type casters (e.g., std::vector<T>), where nanobind was too aggressive in its use of move semantics. Calling a bound function from Python taking such a list (e.g., f([t1, t2, ..])) would destruct t1, t2, .. if the type T exposed a move constructor, which is highly non-intuitive and no longer happens as of this fix.

    Further investigation also revealed inefficiencies in the previous implementation where moves were actually possible but not done (e.g., for functions taking an STL vector by value). Some binding projects may see speedups as a consequence of this change. (issue #307, commit 122015).

Version 1.5.2 (Aug 24, 2023)

  • Fixed a severe issue with inheritance of the Py_TPFLAGS_HAVE_GC flag affecting classes that derive from other classes with a nb::dynamic_attr annotation. (issue #279, commit dbedad).

  • Implicit conversion of nd-arrays to conform to contiguity constraints such as c_contig and f_contig previously failed in some cases that are now addressed. (issue #278 commit ed929b).

Version 1.5.1 (Aug 23, 2023)

  • Fixed serious reference counting issue introduced in nanobind version 1.5.0, which affected the functions python_error::traceback() and python_error::what(), causing undefined behavior via use-after-free. Also addressed an unrelated minor UB sanitizer warning. (issue #277, commits 30d30c and c48b18).

  • Extended the internal data structure tag so that it isolates different MSVC versions from each other (they are often not ABI compatible, see pybind11 issue #4779). This means that nanobind 1.5.1 effectively bumps the internal ABI version to “10.5” when compiling for MSVC, and the internals will be isolated from extensions built with nanobind v1.5.0 or older. (commit c7f3cd).

  • Incorporated fixes so that nanobind works with PyPy 3.10. (commits fb5508 and 2ed108).

  • Fixed type caster for std::vector<bool>. (PR #256).

  • Fixed compilation in debug mode on MSVC. (PR #253).

Version 1.5.0 (Aug 7, 2023)

Version 1.4.0 (June 8, 2023)

  • Improved the efficiency of the function dispatch loop. (PR #227).

  • Significant improvements to the Eigen type casters (generalized stride handling to avoid unnecessary copies, support for conversion via nb::cast(), many refinements to the Eigen::Ref<T> interface). (PR #215).

  • Added a NB_DOMAIN parameter to nanobind_add_module() which can isolate extensions from each other to avoid binding clashes. See the associated FAQ entry for details. (commit 977119).

  • Reduced the severity of nanobind encountering a duplicate type binding (commits f3b0e6, and 2c9124).

  • Support for pickling/unpickling nanobind objects. (commit 59843e).

  • Internal ABI version 9.

Version 1.3.2 (June 2, 2023)

  • Fixed compilation on 32 bit processors (only i686 tested so far). (PR #224).

  • Fixed compilation on PyPy 3.8. (commit cd8135).

  • Reduced binary bloat of musllinux wheels. (commit f52513).

Version 1.3.1 (May 31, 2023)

  • CMake build system improvements for stable ABI wheel generation. (PR #222).

Version 1.3.0 (May 31, 2023)

This is a big release. The sections below cover added features, efficiency improvements, and miscellaneous fixes and improvements.

New features

  • nanobind now supports binding types that inherit from std::enable_shared_from_this<T>. See the advanced section on object ownership for more details. (PR #212).

  • Added a type caster between Python datetime/timedelta objects and C++ std::chrono::duration/std::chrono::time_point, ported from pybind11. (PR #175).

  • The nb::ndarray<..> class can now use the buffer protocol to receive and return arrays representing read-only memory. (PR #217).

  • Added nb::python_error::discard_as_unraisable() as a wrapper around PyErr_WriteUnraisable(). (PR #175).

Efficiency improvements:

  • Reduced the per-instance overhead of nanobind by 1 pointer and simplified the internal hash table types to crunch libnanobind. (commit de018d).

  • Supplemental type data specified via nb::supplement<T>() is now stored directly within the type object instead of being referenced through an indirection. (commit d82ca9).

  • Reduced the number of exception-related exports to further crunch libnanobind. (commit 763962).

  • Reduced the size of nanobind type objects by 5 pointers. (PR #194, #195, and commit d82ca9).

  • Internal nanobind types (nb_type, nb_static_property, nb_ndarray) are now constructed on demand. This reduces the size of the libnanobind component in static (NB_STATIC) builds when those features are not used. (commits 95e45a, 375083, and e033c8).

  • Added a small function cache to improve code generation in limited API builds. (commit f0f42a).

  • Refined compiler and linker flags across platforms to ensure compact binaries especially in NB_STATIC builds. (commit 5ead9f)

  • nanobind enums now take advantage of supplemental data to improve the speed of object and name lookups. Note that this prevents use of nb::supplement<T>() with enums for other purposes. (PR #195).

Miscellaneous fixes and improvements

  • Use the new PEP-697 interface to access data in type objects when compiling stable ABI3 wheels. This improves forward compatibility (the Python team may at some point significantly refactor the layout and internals of type objects). (PR #211):

  • Added introspection attributes __self__ and __func__ to nanobind bound methods, to make them more like regular Python bound methods. Fixed a bug where some_obj.method.__call__() would behave differently than some_obj.method(). (PR #216).

  • Updated the implementation of nb::enum_ so it does not take advantage of any private nanobind type details. As a side effect, the construct nb::class_<T>(..., nb::is_enum(...)) is no longer permitted; use nb::enum_<T>(...) instead. (PR #195).

  • Added the nb::type_slots_callback class binding annotation, similar to nb::type_slots but allowing more dynamic choices. (PR #195).

  • nanobind type objects now treat attributes specially whose names begin with @. These attributes can be set once, but not rebound or deleted. This safeguard allows a borrowed reference to the attribute value to be safely stashed in the type supplement, allowing arbitrary Python data associated with the type to be accessed without a dictionary lookup while keeping this data visible to the garbage collector. (PR #195).

  • Fixed surprising behavior in enumeration comparisons and arithmetic (PR #207):

    • Enum equality comparisons (== and !=) now can only be true if both operands have the same enum type, or if one is an enum and the other is an int. This resolves some confusing results and ensures that enumerators of different types have a distinct identity, which is important if they’re being put into the same set or used as keys in the same dictionary. All of the following were previously true but will now evaluate as false:

      • FooEnum(1) == BarEnum(1)

      • FooEnum(1) == 1.2

      • FooEnum(1) == "1"

    • Enum ordering comparisons (<, <=, >=, >) and arithmetic operations (when using the is_arithmetic annotation) now require that any non-enum operand be a Python number (an object that defines __int__, __float__, and/or __index__) and will avoid truncating non-integer operands to integers. Note that unlike with equality comparisons, ordering and arithmetic operations do still permit two operands that are enums of different types. Some examples of changed behavior:

      • FooEnum(1) < 1.2 is now true (used to be false)

      • FooEnum(2) * 1.5 is now 3.0 (used to be 2)

      • FooEnum(3) - "2" now raises an exception (used to be 1)

    • Enum comparisons and arithmetic operations with unsupported types now return NotImplemented rather than raising an exception. This means equality comparisons such as some_enum == None will return unequal rather than failing; order comparisons such as some_enum < None will still fail, but now with a more informative error.

  • Internal ABI version 8.

Version 1.2.0 (April 24, 2023)

  • Improvements to the internal C++ → Python instance map data structure to improve performance and address type confusion when returning previously registered instances. (commit 716354, discussion 189).

  • Added up-to-date nanobind benchmarks on Linux including comparisons to Cython. (commit 834cf3 and e9e163).

  • Removed the superfluous nb_enum metaclass. (commit 9c1985).

  • Fixed a corner case that prevented nb::cast<char> from working. (commit 9ae320).

Version 1.1.1 (April 6, 2023)

  • Added documentation on packaging and distributing nanobind modules. (commit 0715b2).

  • Made the conversion handle::operator bool() explicit. (PR #173).

  • Support nb::typed<..> in return values. (PR #174).

  • Tweaks to definitions in nb_types.h to improve compatibility with further C++ compilers (that said, there is no change about the official set of supported compilers). (commit b8bd10)

Version 1.1.0 (April 5, 2023)

  • Added size, shape_ptr, stride_ptr members to to the nb::ndarray<..> class. (PR #161).

  • Allow macros in NB_MODULE(..) name parameter. (PR #168).

  • The nb::ndarray<..> interface is more tolerant when converting Python (PyTorch/NumPy/..) arrays with a size-0 dimension that have mismatched strides. (PR #162).

  • Removed the <anonymous> label from docstrings of anonymous functions, which caused issues in MyPy. (PR #172).

  • Fixed an issue in the propagation of return value policies that broke user-provided/custom policies in properties (PR #170).

  • The Eigen interface now converts 1x1 matrices to 1x1 NumPy arrays instead of scalars. (commit 445781).

  • The nanobind package now has a simple command line interface. (commit d5ccc8).

Version 1.0.0 (March 28, 2023)

  • Nanobind now has a logo. (commit b65d3b).

  • Fixed a subtle issue involving function/method properties and the IPython command line interface. (PR #151).

  • Added a boolean type to the nb::ndarray<..> interface. (PR #150).

  • Minor fixes and improvements.

Version 0.3.1 (March 8, 2023)

  • Added a type caster for std::filesystem::path. (PR #138 and commit 0b05cd).

  • Fixed technical issues involving implicit conversions (commits 022935 and 5aefe3) and construction of type hierarchies with custom garbage collection hooks (commit 022935).

  • Re-enabled the ‘chained fixups’ linker optimization for recent macOS deployment targets. (commit 2f29ec).

Version 0.3.0 (March 8, 2023)

  • Botched release, replaced by 0.3.1 on the same day.

Version 0.2.0 (March 3, 2023)

  • Nanobind now features documentation on readthedocs.

  • The documentation process revealed a number of inconsistencies in the class_<T>::def* naming scheme. nanobind will from now on use the following shortened and more logical interface:

    Type

    method

    Methods & constructors

    .def()

    Fields

    .def_ro(), .def_rw()

    Properties

    .def_prop_ro(), .def_prop_rw()

    Static methods

    .def_static()

    Static fields

    .def_ro_static(), .def_rw_static()

    Static properties

    .def_prop_ro_static(), .def_prop_rw_static()

    Compatibility wrappers with deprecation warnings were also added to help port existing code. They will be removed when nanobind reaches version 1.0. (commits cb0dc3 and b5ed69)

  • The nb::tensor<..> class has been renamed to nb::ndarray<..>, and it is now located in a different header file (nanobind/ndarray.h). A compatibility wrappers with a deprecation warning was retained in the original header file. It will be removed when nanobind reaches version 1.0. (commit a6ab8b).

  • Dropped the first two arguments of the NB_OVERRIDE_*() macros that turned out to be unnecessary in nanobind. (commit 22bc21).

  • Added casters for dense matrix/array types from the Eigen library. (PR #120).

  • Added casters for sparse matrix/array types from the Eigen library. (PR #126).

  • Implemented nb::bind_vector<T>() analogous to similar functionality in pybind11. (commit f2df8a).

  • Implemented nb::bind_map<T>() analogous to similar functionality in pybind11. (PR #114).

  • nanobind now automatically downcasts polymorphic objects in return values analogous to pybind11. (commit cab96a).

  • nanobind now supports tag-based polymorphism. (commit 214260).

  • Updated tuple/list iterator to satisfy the std::forward_iterator concept. (PR #117).

  • Fixed issues with non-writeable tensors in NumPy. (commit 25cc3c).

  • Removed use of some C++20 features from the codebase. This now makes it possible to use nanobind on Visual Studio 2017 and GCC 7.3.1 (used on RHEL 7). (PR #115).

  • Added the nb::typed<...> wrapper to override the type signature of an argument in a bound function in the generated docstring. (commit b3404c).

  • Added an nb::implicit_convertible<A, B>() function analogous to the one in pybind11. (commit aba4af).

  • Updated nb::make_*_iterator<..>() so that it returns references of elements, not copies. (commit 8916f5).

  • Changed the CMake build system so that the library component (libnanobind) is now compiled statically by default. (commit 1365f5).

  • Switched shared library linking on macOS back to a two-level namespace. (commit a617fb).

  • Various minor fixes and improvements.

  • Internal ABI version 7.

Version 0.1.0 (January 3, 2023)

  • Allow nanobind methods on non-nanobind) classes. (PR #104).

  • Fix dangling tp_members pointer in type initialization. (PR #99).

  • Added a runtime setting to suppress leak warnings. (PR #109).

  • Added the ability to hash nb::enum_<..> instances (PR #106).

  • Fixed the signature of nb::enum_<..>::export_values(). (commit 714d17).

  • Double-check GIL status when performing reference counting operations in debug mode. (commit a1b245).

  • Fixed a reference leak that occurred when module initialization fails. (commit adfa9e).

  • Improved robustness of nb::tensor<..> caster. (commit 633672).

  • Upgraded the internally used tsl::robin_map<> hash table to address a rare overflow issue discovered in this codebase. (commit 3b81b1).

  • Various minor fixes and improvements.

  • Internal ABI version 6.

Version 0.0.9 (Nov 23, 2022)

  • PyPy 7.3.10 or newer is now supported subject to certain limitations. (commits f935f9 and b343bb).

  • Three changes that reduce the binary size and improve runtime performance of binding libraries. (commits 07b4e1, 9a8037, and cba4d2).

  • Fixed a reference leak in python_error::what() (commit 61393a).

  • Adopted a new policy for function type annotations. (commit c855c9).

  • Improved the effectiveness of link-time-optimization when building extension modules with the NB_STATIC flag. This leads to smaller binaries. (commit f64d2b).

  • Nanobind now relies on standard mechanisms to inherit the tp_traverse and tp_clear type slots instead of trying to reimplement the underlying CPython logic (commit efa09a).

  • Moved nanobind internal data structures from builtins to Python interpreter state dictionary. (issue #96, commit ca23da).

  • Various minor fixes and improvements.

Version 0.0.8 (Oct 27, 2022)

  • Caster for std::array<..>. (commit be34b1).

  • Caster for std::set<..> and std::unordered_set (PR #87).

  • Ported nb::make[_key_,_value]_iterator() from pybind11. (commit 34d0be).

  • Caster for untyped void * pointers. (commit 6455ff).

  • Exploit move constructors in nb::class_<T>::def_readwrite() and nb::class_<T>::def_readwrite_static() (PR #94).

  • Redesign of the std::function<> caster to enable cyclic garbage collector traversal through inter-language callbacks (PR #95).

  • New interface for specifying custom type slots during Python type construction. (commit 38ba18).

  • Fixed potential undefined behavior related to nb_func garbage collection by Python’s cyclic garbage collector. (commit 662e1b).

  • Added a workaround for spurious reference leak warnings caused by other extension modules in conjunction with typing.py (commit 5e11e8).

  • Various minor fixes and improvements.

  • Internal ABI version 5.

Version 0.0.7 (Oct 14, 2022)

  • Fixed a regression involving function docstrings in pydoc. (commit 384f4a).

Version 0.0.6 (Oct 14, 2022)

  • Fixed undefined behavior that could lead to crashes when nanobind types were freed. (commit 39266e).

  • Refactored nanobind so that it works with Py_LIMITED_API (PR #37).

  • Dynamic instance attributes (PR #38).

  • Intrusive pointer support (PR #43).

  • Byte string support (PR #62).

  • Casters for std::variant<..> and std::optional<..> (PR #67).

  • Casters for std::map<..> and std::unordered_map<..> (PR #73).

  • Caster for std::string_view<..> (PR #68).

  • Custom exception support (commit 41b7da).

  • Register nanobind functions with Python’s cyclic garbage collector (PR #86).

  • Various minor fixes and improvements.

  • Internal ABI version 3.

Version 0.0.5 (May 13, 2022)

  • Enumeration export.

  • Implicit number conversion for NumPy scalars.

  • Various minor fixes and improvements.

Version 0.0.4 (May 13, 2022)

  • Botched release, replaced by 0.0.5 on the same day.

Version 0.0.3 (Apr 14, 2022)

  • DLPack support.

  • Iterators for various Python type wrappers.

  • Low-level interface to instance creation.

  • Docstring generation improvements.

  • Various minor fixes and improvements.

Version 0.0.2 (Mar 10, 2022)

  • Initial release of the nanobind codebase.

  • Internal ABI version 1.

Version 0.0.1 (Feb 21, 2022)

  • Placeholder package on PyPI.