Skip to main content
Stability: 2 - Stable
Node-API (formerly N-API) is an API for building native addons. It is independent from the underlying JavaScript runtime (V8) and is maintained as part of Node.js itself.

Overview

Node-API provides an Application Binary Interface (ABI) stable API across versions of Node.js. It:
  • Insulates addons from changes in the underlying JavaScript engine
  • Allows modules compiled for one major version to run on later versions without recompilation
  • Uses the same approach/tools as C++ Addons (node-gyp, etc.)
  • Provides a different set of APIs focused on ABI stability

Key Features

  • ABI Stability: Binary compatibility across Node.js versions
  • Version Independent: No need to recompile for new Node.js releases
  • Status-based Error Handling: All calls return napi_status
  • Opaque Types: JavaScript values abstracted behind napi_value
  • Multiple Language Support: Can be used from C, C++, Rust, and other languages

Building with Node-API

Unlike modules written in JavaScript, developing Node-API addons requires:
  1. C/C++ Toolchain
    • Linux: GCC or LLVM
    • macOS: Xcode command line tools (xcode-select --install)
    • Windows: Visual Studio or npm install --global windows-build-tools
  2. Build Tools
    • node-gyp: Most common, uses GYP build system
    • CMake.js: Alternative using CMake
  3. Deployment Options
    • node-pre-gyp: Upload binaries to custom servers
    • prebuild: Upload binaries to GitHub releases
    • prebuildify: Bundle binaries with npm package

Usage

Include the Node-API header:
#include <node_api.h>
This opts into the default NAPI_VERSION for the Node.js release.

Specifying Version

For compatibility with specific Node-API versions:
#define NAPI_VERSION 3
#include <node_api.h>

Experimental Features

To use experimental APIs:
#define NAPI_EXPERIMENTAL
#include <node_api.h>

Node-API Version Matrix

Node-API versions are additive up to version 9. From version 9 onwards, add-ons may need code updates between major versions while maintaining ABI stability.
Node-API VersionSupported In
10v22.14.0+, 23.6.0+ and later
9v18.17.0+, 20.3.0+, 21.0.0+
8v12.22.0+, v14.17.0+, v15.12.0+, 16.0.0+
7v10.23.0+, v12.19.0+, v14.12.0+, 15.0.0+
6v10.20.0+, v12.17.0+, 14.0.0+

Basic Data Types

napi_status

Integral status code indicating success or failure:
typedef enum {
  napi_ok,
  napi_invalid_arg,
  napi_object_expected,
  napi_string_expected,
  napi_function_expected,
  napi_number_expected,
  napi_boolean_expected,
  napi_array_expected,
  napi_generic_failure,
  napi_pending_exception,
  napi_cancelled,
  napi_escape_called_twice,
  // ...
} napi_status;

napi_env

Represents a context for Node-API operations. Must be passed to most Node-API functions.
Do not cache or share napi_env between Worker threads. Each thread receives its own napi_env.

napi_value

Opaque pointer representing a JavaScript value.

napi_callback

Function pointer type for native functions exposed to JavaScript:
typedef napi_value (*napi_callback)(napi_env env, napi_callback_info info);

Error Handling

Node-API uses both return values and JavaScript exceptions for error handling.

Return Values

All Node-API functions return napi_status:
  • napi_ok: Success, no exception
  • napi_pending_exception: Exception pending, no error
  • Other values: Error occurred

Getting Error Information

napi_status napi_get_last_error_info(node_api_basic_env env,
                                     const napi_extended_error_info** result);
Returns detailed error information including:
  • error_message: Human-readable error description
  • error_code: Node-API status code
  • engine_error_code: VM-specific error code

Throwing Exceptions

// Throw generic error
napi_status napi_throw_error(napi_env env,
                             const char* code,
                             const char* msg);

// Throw TypeError
napi_status napi_throw_type_error(napi_env env,
                                  const char* code,
                                  const char* msg);

// Throw RangeError
napi_status napi_throw_range_error(napi_env env,
                                   const char* code,
                                   const char* msg);

Creating Error Objects

napi_status napi_create_error(napi_env env,
                              napi_value code,
                              napi_value msg,
                              napi_value* result);

napi_status napi_create_type_error(napi_env env,
                                   napi_value code,
                                   napi_value msg,
                                   napi_value* result);

Working with JavaScript Values

Creating Values

// Create string
napi_status napi_create_string_utf8(napi_env env,
                                    const char* str,
                                    size_t length,
                                    napi_value* result);

// Create number
napi_status napi_create_double(napi_env env,
                               double value,
                               napi_value* result);

// Create boolean
napi_status napi_get_boolean(napi_env env,
                             bool value,
                             napi_value* result);

// Create object
napi_status napi_create_object(napi_env env,
                               napi_value* result);

// Create array
napi_status napi_create_array(napi_env env,
                              napi_value* result);

Type Checking

napi_status napi_typeof(napi_env env,
                        napi_value value,
                        napi_valuetype* result);

napi_status napi_is_array(napi_env env,
                          napi_value value,
                          bool* result);

Converting Values

// Get string
napi_status napi_get_value_string_utf8(napi_env env,
                                       napi_value value,
                                       char* buf,
                                       size_t bufsize,
                                       size_t* result);

// Get number
napi_status napi_get_value_double(napi_env env,
                                  napi_value value,
                                  double* result);

// Get boolean
napi_status napi_get_value_bool(napi_env env,
                                napi_value value,
                                bool* result);

Working with Objects

Setting Properties

napi_status napi_set_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8name,
                                    napi_value value);

napi_status napi_set_property(napi_env env,
                              napi_value object,
                              napi_value key,
                              napi_value value);

Getting Properties

napi_status napi_get_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8name,
                                    napi_value* result);

napi_status napi_get_property(napi_env env,
                              napi_value object,
                              napi_value key,
                              napi_value* result);

Checking Properties

napi_status napi_has_named_property(napi_env env,
                                    napi_value object,
                                    const char* utf8name,
                                    bool* result);

Working with Functions

Creating Functions

napi_status napi_create_function(napi_env env,
                                 const char* utf8name,
                                 size_t length,
                                 napi_callback cb,
                                 void* data,
                                 napi_value* result);

Calling Functions

napi_status napi_call_function(napi_env env,
                               napi_value recv,
                               napi_value func,
                               size_t argc,
                               const napi_value* argv,
                               napi_value* result);

Getting Callback Info

napi_status napi_get_cb_info(napi_env env,
                             napi_callback_info cbinfo,
                             size_t* argc,
                             napi_value* argv,
                             napi_value* this_arg,
                             void** data);

Memory Management

Handle Scopes

Handle scopes manage the lifetime of napi_value objects:
// Open handle scope
napi_status napi_open_handle_scope(napi_env env,
                                   napi_handle_scope* result);

// Close handle scope
napi_status napi_close_handle_scope(napi_env env,
                                    napi_handle_scope scope);

References

References allow control over object lifetimes:
// Create reference
napi_status napi_create_reference(napi_env env,
                                  napi_value value,
                                  uint32_t initial_refcount,
                                  napi_ref* result);

// Delete reference
napi_status napi_delete_reference(napi_env env,
                                  napi_ref ref);

// Get reference value
napi_status napi_get_reference_value(napi_env env,
                                     napi_ref ref,
                                     napi_value* result);

Instance Data

Associate data with a Node.js environment instance:
// Set instance data
napi_status napi_set_instance_data(node_api_basic_env env,
                                   void* data,
                                   napi_finalize finalize_cb,
                                   void* finalize_hint);

// Get instance data
napi_status napi_get_instance_data(node_api_basic_env env,
                                   void** data);

Async Operations

Async Work

// Create async work
napi_status napi_create_async_work(napi_env env,
                                   napi_value async_resource,
                                   napi_value async_resource_name,
                                   napi_async_execute_callback execute,
                                   napi_async_complete_callback complete,
                                   void* data,
                                   napi_async_work* result);

// Queue async work
napi_status napi_queue_async_work(napi_env env,
                                  napi_async_work work);

Thread-safe Functions

// Create thread-safe function
napi_status napi_create_threadsafe_function(
    napi_env env,
    napi_value func,
    napi_value async_resource,
    napi_value async_resource_name,
    size_t max_queue_size,
    size_t initial_thread_count,
    void* thread_finalize_data,
    napi_finalize thread_finalize_cb,
    void* context,
    napi_threadsafe_function_call_js call_js_cb,
    napi_threadsafe_function* result);

// Call thread-safe function
napi_status napi_call_threadsafe_function(
    napi_threadsafe_function func,
    void* data,
    napi_threadsafe_function_call_mode is_blocking);

Example: Hello World

#include <node_api.h>

static napi_value Method(napi_env env, napi_callback_info info) {
  napi_status status;
  napi_value greeting;
  
  status = napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &greeting);
  if (status != napi_ok) return NULL;
  
  return greeting;
}

static napi_value Init(napi_env env, napi_value exports) {
  napi_status status;
  napi_value fn;

  status = napi_create_function(env, NULL, 0, Method, NULL, &fn);
  if (status != napi_ok) return NULL;

  status = napi_set_named_property(env, exports, "hello", fn);
  if (status != napi_ok) return NULL;

  return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

C++ Wrapper: node-addon-api

For C++ developers, node-addon-api provides a more efficient wrapper:
#include <napi.h>

Napi::String Method(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  return Napi::String::New(env, "world");
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set("hello", Napi::Function::New(env, Method));
  return exports;
}

NODE_API_MODULE(hello, Init)

Best Practices

  1. Check Return Values: Always check napi_status return values
  2. Handle Scopes: Properly manage handle scope lifetimes
  3. Error Handling: Use appropriate error handling for both sync and async operations
  4. Thread Safety: Use thread-safe functions for cross-thread communication
  5. Memory Management: Use references and finalizers to manage object lifetimes
  6. Version Compatibility: Define appropriate NAPI_VERSION for your needs

Further Resources