Open-source project
nodejs/nan avatar
nodejs/nan

NAN: Native Abstractions for Node.js Native Addon Development

GitHub describes it as Native Abstractions for Node.js. The repository metadata lists C++ as its primary language. The metadata lists the MIT license. This article stays within the project description and details documented in the GitHub repository README.

3,356 stars531 forksC++MIT

At a glance

What is it?
NAN is a C++ header library maintained by the Node.js project that insulates native addon code from V8 API breaking changes across Node.js versions 8 through 26. It trades direct V8 API access for a stable abstraction layer that keeps addons compiling without constant maintenance across major Node.js releases.
Who is it for?
NAN suits developers who maintain C++ addons across a wide range of Node.js versions and cannot afford to rewrite method signatures on every major V8 release. Developers starting a new addon against Node.js 18 or later should evaluate Node-API (napi.h) first: it is part of the Node.js core, provides a stable C ABI, and does not require updating when Node.js upgrades.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The Problem NAN Addresses in Native Addon Development

Building a native Node.js addon means writing C++ that calls the V8 JavaScript engine directly. The V8 API is not stable across Node.js major versions. A method signature that compiles against Node.js 10 may fail against Node.js 12, and Node.js 4 introduced incompatibilities significant enough that maintaining an addon across the 0.10-to-0.12-to-4.0 transition was, in the README's words, 'a minor nightmare'.

NAN stores all the conditional logic for handling these API differences in a single header file. An addon author includes nan.h and uses the NAN macro and utility layer instead of calling V8 directly. NAN's macros expand to the correct V8 calls for the detected version at compile time. The addon author writes one set of code, and NAN handles the per-version dispatch internally.

The current version is 2.29.0 and the supported range runs from Node.js 8 through Node.js 26, covering 14 major versions.

What the Header File Abstracts

NAN provides several categories of abstraction. The JavaScript-accessible method layer replaces the varying callback types across V8 versions with a unified interface based on Nan::FunctionCallbackInfo and Nan::PropertyCallbackInfo, plus Nan::ReturnValue for returning values from callbacks.

Handle scopes are another V8 API area where creation syntax changed across versions. NAN provides Nan::HandleScope and Nan::EscapableHandleScope as drop-in replacements that work identically across the supported version range.

For asynchronous work, NAN provides Nan::AsyncWorker, which wraps libuv's work queue and manages the handoff between the thread pool and the main V8 thread. The test suite in test/cpp covers the full range of use cases including AsyncWorker, AsyncProgressWorker, AsyncProgressQueueWorker, accessors, interceptors, JSON parse and stringify, buffer handling, garbage collection callbacks, and persistent handles.

NAN also provides Nan::ObjectWrap, which attaches a C++ object to a JavaScript object so the garbage collector can manage the lifetime of both together. Persistent handle types are covered by Nan::Persistent with separate inline implementations for Node.js versions before and after 12.

Installing NAN and Wiring It into a Native Addon

Add NAN as a dependency with any Node.js package manager:

bash
npm install nan

NAN is a header-only library. After installing, pull its path into the addon's binding.gyp file so the C++ compiler can find nan.h:

python
"include_dirs" : [
    "<!(node -e \"require('nan')\")"
]

This line runs node at build time to resolve the NAN package path and passes it as a compiler include directory. After this, any .cpp file in the addon can use `#include <nan.h>` and then call the NAN macros and types directly.

To rebuild the test suite, the Makefile provides:

bash
node-gyp rebuild --directory test

The test runner is tap, invoked via `npm test`, which runs all test files matching `test/js/*-test.js`.

Where NAN Falls Short: Node-API and the ABI Stability Gap

NAN abstracts source-level compatibility: addon code that uses NAN compiles against any supported Node.js version without code changes. However, the compiled binary is still tied to a specific Node.js major version. When you upgrade Node.js, you must recompile the addon.

Node-API (napi.h), which is part of the Node.js core since version 6 and is now the recommended approach for new addons, provides a stable C ABI. A binary compiled against Node-API can load in any later Node.js version without recompilation. NAN does not offer this guarantee.

For addon authors who distribute prebuilt binaries to end users, the recompile requirement is a meaningful constraint. When a user upgrades Node.js, any NAN-based addon may throw a NODE_MODULE_VERSION mismatch error at load time and require rebuilding. Node-API addons are immune to this because the binary interface does not change between Node.js releases.

Async Workers and the Thread Pool Integration

The async pi estimation example in `examples/async_pi_estimate/` demonstrates the two main patterns for asynchronous work in NAN. The synchronous version wraps the estimation function in a regular method call. The async version uses `Nan::AsyncWorker` to move the computation off the main thread.

An AsyncWorker subclass overrides the `Execute()` method (which runs on a libuv thread pool thread) and the `HandleOKCallback()` method (which runs on the main V8 thread after the work completes). NAN manages the transition between these two contexts and handles error propagation. The addon author does not interact with libuv directly.

AsyncProgressWorker extends this pattern with a mechanism to send intermediate results from the worker thread back to the main thread during execution, which is useful for streaming large outputs or for progress-reporting tasks. AsyncProgressQueueWorker adds a queue so that multiple progress updates are not dropped if the main thread is busy.

Maintenance Status and Node.js Project Governance

The last push to the NAN repository was on 2026-09-14. The project is maintained under the nodejs GitHub organization, not as an individual or third-party project. The contributors list in package.json includes the original author Rod Vagg and seven co-authors.

The repository uses node-gyp for building, cpplint for C++ lint checks, and a pre-commit configuration file at .pre-commit-config.yaml. CI runs on AppVeyor for Windows coverage. Governance and contributing guidelines are in the README under the Governance and Contributing section.

NAN is MIT licensed. There are no usage restrictions for commercial addons.

The repository layout separates header files by version: nan_callbacks_12_inl.h and nan_callbacks_pre_12_inl.h provide the version-specific implementations for callback types, nan_persistent_12_inl.h and nan_persistent_pre_12_inl.h handle persistent references, and nan_maybe_43_inl.h and nan_maybe_pre_43_inl.h cover the Maybe and MaybeLocal types introduced in V8 4.3. The main nan.h header includes the correct variant based on the detected Node.js version at compile time. This split keeps the per-version logic isolated and auditable without requiring addon authors to read it.

NAN versus Node-API: Which One to Choose

NAN covers Node.js 8 through 26 with a single source-compatible header. Node-API covers Node.js 6 and later with an ABI-stable binary-compatible interface. The choice depends on the requirements of the addon.

If the addon targets Node.js versions before 6, NAN is the only option. If the addon targets Node.js 6 or later and the priority is deploying prebuilt binaries that do not need recompilation when users upgrade Node.js, Node-API is the better foundation.

For existing addons already written with NAN, migration to Node-API is non-trivial because the two APIs have different type systems and different patterns for handle scopes and persistent references. NAN's value is in stability for an existing codebase, not as the recommended starting point for new addons on current Node.js versions.

Editorial conclusion

NAN suits developers who maintain C++ addons across a wide range of Node.js versions and cannot afford to rewrite method signatures on every major V8 release. Developers starting a new addon against Node.js 18 or later should evaluate Node-API (napi.h) first: it is part of the Node.js core, provides a stable C ABI, and does not require updating when Node.js upgrades. NAN remains the correct choice for addons that must support Node.js versions earlier than 6, where Node-API is not available, or for teams already invested in NAN's type system and async worker patterns.

Frequently asked questions

What is the nodejs/nan library used for in native addon development?

NAN provides a C++ header layer that absorbs V8 API changes across Node.js versions 8 through 26. It lets addon authors write one set of code using NAN's unified macro layer instead of writing per-version conditional code to handle the varying V8 callback and handle scope signatures.

Does a NAN-compiled addon need to be rebuilt when upgrading Node.js?

Yes. NAN provides source-level compatibility, not binary compatibility. Each compiled addon binary is tied to a specific Node.js major version. Users who upgrade Node.js must rebuild any NAN-based addons. Node-API addons do not have this limitation.

How does Nan::AsyncWorker differ from calling libuv directly?

Nan::AsyncWorker manages the full lifecycle of a libuv work queue entry: it queues the task, manages thread pool execution of the Execute() method, and dispatches the callback back to the main V8 thread via HandleOKCallback() or HandleErrorCallback(). The addon author implements those two methods and does not interact with libuv's uv_queue_work directly.

Official sources

  1. Official README
  2. Project repository
Community notes

Community notes