Node-API in Node.js: A Complete Guide to Native Addon Development

Node-API (formerly N-API) is a stable API for building native Addons in Node.js. . It is independent of the underlying JavaScript engine (such as V8) and maintained as part of Node.js itself. Its primary goal is to guarantee ABI stability, ensuring that modules compiled for one major version of Node.js can run on later versions without recompilation. This makes Addon development more reliable and future-proof.

ABI Stabilitynode-addon-apinapi_statusError HandlingBuild Tools (node-gyp, CMake.js)Precompiled Binaries (node-pre-gyp, prebuild, prebuildify)Node-API Version Matrix

~14 min read • Updated Dec 26, 2025

1. Features of Node-API


  • All Node-API calls return a status code of type napi_status.
  • JavaScript values are abstracted behind the opaque type napi_value.
  • Error details can be retrieved using napi_get_last_error_info.

2. Writing Addons in Different Languages


Node-API is a C-based API that guarantees ABI stability. This allows Addons to be written in other programming languages. The node-addon-api library provides a C++ wrapper for easier development.

// node-addon-api
Object obj = Object::New(env);
obj["foo"] = String::New(env, "bar");

3. ABI Stability


To remain ABI-compatible across Node.js versions, Addons must use #include <node_api.h>. Other APIs such as V8 or libuv do not provide ABI stability guarantees.

4. Enums in Node-API


All enums are treated as int32_t. New values may be added without removal or renaming, so code should always handle unknown values safely.

5. Build Tools


  • node-gyp: Traditional build system bundled with npm, based on GYP.
  • CMake.js: Alternative build system for projects already using CMake.

6. Precompiled Binaries


  • node-pre-gyp: Supports uploading binaries to servers, especially Amazon S3.
  • prebuild: Uploads binaries to GitHub releases.
  • prebuildify: Bundles binaries with npm packages for immediate availability.

7. Node-API Versions


From version 9 onward, Node-API versions are additive but may require updates for newer versions. By default, Node.js provides version 8 unless #define NAPI_VERSION is specified.

Node-API VersionSupported In
10v22.14.0+, v23.6.0+
9v18.17.0+, v20.3.0+, v21.0.0+
8v12.22.0+, v14.17.0+, v15.12.0+, v16.0.0+
7v10.23.0+, v12.19.0+, v14.12.0+, v15.0.0+

8. Separating Node.js-Specific Code


Node.js-specific entry points can be separated from the core functionality, allowing the same code to compile against other Node-API implementations.

// addon.h
#include 
napi_value create_addon(napi_env env);

Conclusion


Node-API provides a stable, engine-independent layer for building native Addons in Node.js. By ensuring ABI stability, developers can create modules that continue to work across Node.js versions without recompilation, making Addon development more robust and future-proof.

1. Managing Environment Data


  • napi_set_instance_data: Associates data with the current environment, tied to its life cycle.
  • napi_get_instance_data: Retrieves data previously associated with the environment.
// Example
napi_set_instance_data(env, data, finalize_cb, NULL);
napi_get_instance_data(env, &retrievedData);

2. Basic Node-API Data Types


  • napi_status: Indicates success or failure of an API call.
  • napi_extended_error_info: Provides detailed error information including message and code.
  • napi_env: Represents the environment context for Node-API calls.
  • napi_value: Opaque pointer representing a JavaScript value.

3. Thread-Safe Functions


napi_threadsafe_function allows JavaScript functions to be called safely from multiple threads.

  • napi_tsfn_release / napi_tsfn_abort: Modes for releasing or closing thread-safe functions.
  • napi_tsfn_nonblocking / napi_tsfn_blocking: Modes for handling queue behavior when full.

4. Object Lifetime Management


  • napi_handle_scope: Controls the lifetime of objects created within a scope.
  • napi_escapable_handle_scope: Allows values created in a scope to escape to a parent scope.
  • napi_ref: Manages references to JavaScript values and their lifetimes.
  • napi_type_tag: Tags objects with a UUID to ensure type safety.

5. Cleanup Hooks


napi_async_cleanup_hook_handle manages asynchronous cleanup events and must be released when cleanup is complete.

6. Callback Types


  • napi_callback_info: Provides context information when a callback is invoked.
  • napi_callback: Standard function signature for native functions exposed to JavaScript.
typedef napi_value (*napi_callback)(napi_env, napi_callback_info);

Conclusion


Environment Life Cycle APIs in Node.js enable safe management of data, objects, and functions across multiple environments and threads. These APIs are essential for native Addons that need to interact with multiple contexts, ensuring proper control of object lifetimes and environment-specific data.

1. Finalizers in Node-API


  • node_api_basic_finalize: Called when objects with external data are garbage-collected. Only APIs that accept node_api_basic_env can be used here.
  • napi_finalize: Used to schedule Node-API calls after a garbage collection cycle has completed.

2. Asynchronous Callbacks


  • napi_async_execute_callback: Executes asynchronous operations without interacting directly with JavaScript.
  • napi_async_complete_callback: Completes asynchronous operations and interacts with JavaScript safely.
  • napi_threadsafe_function_call_js: Safely invokes JavaScript functions from secondary threads.

3. Cleanup Hooks


  • napi_cleanup_hook: Called when the environment is being torn down.
  • napi_async_cleanup_hook: Initiates asynchronous cleanup actions during environment teardown.

4. Error Handling with Node-API


All Node-API functions return a napi_status value:

  • napi_ok: Success.
  • napi_pending_exception: A JavaScript exception is pending.
  • Other values indicate specific errors.

Detailed error information can be retrieved using napi_get_last_error_info, which returns a napi_extended_error_info structure containing the error message and code.

5. Exception Management


  • napi_throw: Throws a JavaScript value as an exception.
  • napi_throw_error: Creates and throws a JavaScript Error with a message.
  • napi_throw_type_error: Throws a TypeError.
  • napi_throw_range_error: Throws a RangeError.
  • node_api_throw_syntax_error: Throws a SyntaxError.

Utility functions such as napi_create_error and napi_create_type_error allow developers to construct error objects programmatically.

Conclusion


Finalizers and error handling in Node-API are essential for managing resources and ensuring safe interaction between native code and JavaScript. By using these APIs correctly, developers can build stable, secure, and forward-compatible native Addons for Node.js.

1. Creating Errors in Node-API


  • napi_create_range_error: Creates a JavaScript RangeError with the provided message.
  • node_api_create_syntax_error: Creates a JavaScript SyntaxError with the provided message.
// Example
napi_value error;
napi_create_range_error(env, NULL, msg, &error);

2. Exception Management


  • napi_get_and_clear_last_exception: Retrieves and clears the last pending exception.
  • napi_is_exception_pending: Checks if an exception is currently pending.
  • napi_fatal_exception: Triggers an uncaught exception in JavaScript.
  • napi_fatal_error: Terminates the process immediately in case of unrecoverable errors.

3. Object Lifetime Management


Handles returned by Node-API must be managed carefully to prevent premature garbage collection or memory leaks.

  • napi_open_handle_scope / napi_close_handle_scope: Open and close scopes to control handle lifetimes.
  • napi_open_escapable_handle_scope: Allows one handle to escape to an outer scope.
  • napi_escape_handle: Promotes a handle to be valid in the parent scope.

4. Persistent References


  • napi_create_reference: Creates a persistent reference with an initial reference count.
  • napi_delete_reference: Deletes a reference, allowing the object to be garbage-collected.
  • napi_reference_ref: Increments the reference count for a persistent reference.

Persistent references are essential when objects need to remain alive across multiple native method calls. Proper management prevents memory leaks and ensures safe cleanup.

Conclusion


By using napi_create_range_error and other error-handling APIs, developers can safely generate JavaScript errors from native code. Combined with handle scopes and persistent references, Node-API provides a robust framework for managing object lifetimes and ensuring memory safety in native Addons.

1. Managing References


  • napi_reference_unref: Decrements the reference count of a napi_ref and returns the new count.
  • napi_get_reference_value: Retrieves the JavaScript value associated with a napi_ref, or NULL if invalid.

2. Cleanup Hooks


To free resources when a Node.js environment exits, developers can register cleanup hooks:

  • napi_add_env_cleanup_hook: Registers a cleanup function to run at environment teardown.
  • napi_remove_env_cleanup_hook: Removes a previously registered cleanup hook.
  • napi_add_async_cleanup_hook: Registers an asynchronous cleanup hook.
  • napi_remove_async_cleanup_hook: Removes an asynchronous cleanup hook.

3. Finalization During Environment Exit


When the Node.js environment is torn down, all napi_finalize callbacks for objects, thread-safe functions, and instance data are invoked. To avoid use-after-free issues, addons should register cleanup hooks to release resources in the correct order.

4. Module Registration


Node-API modules are registered using macros:

  • NAPI_MODULE: Registers an Init function as the entry point.
  • NAPI_MODULE_INIT: A shorthand for defining Init functions.
// Example Init
napi_value Init(napi_env env, napi_value exports) {
  napi_value answer;
  napi_create_int64(env, 42, &answer);
  napi_set_named_property(env, exports, "answer", answer);
  return exports;
}

5. Working with JavaScript Values


Node-API exposes functions to create and manipulate JavaScript values:

  • napi_create_array: Creates a JavaScript Array.
  • napi_create_buffer: Creates a Node.js Buffer.
  • napi_create_date: Creates a JavaScript Date object.

Conclusion


By using napi_reference_unref and cleanup hooks, developers can manage resources safely and prevent memory leaks in native Addons. Combined with APIs for creating JavaScript values, Node-API provides a powerful framework for building stable and efficient native modules in Node.js.

1. External Values


  • napi_create_external: Creates a JavaScript value with attached external data. This value is of type napi_external and does not support additional properties.
  • napi_create_external_arraybuffer: Creates an ArrayBuffer backed by externally allocated memory.
  • napi_create_external_buffer: Creates a Buffer backed by external memory.

All of these APIs support an optional finalize_cb callback, which is invoked when the JavaScript object is garbage-collected, allowing safe cleanup of external resources.

2. Object Creation


  • napi_create_object: Creates a default JavaScript object (equivalent to new Object()).
  • napi_create_object_with_properties: Creates an object with a specified prototype and properties in one atomic operation, improving efficiency.

3. Symbols


  • napi_create_symbol: Creates a new JavaScript Symbol with an optional description.
  • node_api_symbol_for: Retrieves or creates a Symbol in the global registry, ensuring reuse across modules.

4. Typed Arrays and DataView


  • napi_create_typedarray: Creates a TypedArray over an existing ArrayBuffer.
  • napi_create_dataview: Creates a DataView for flexible access to binary data in an ArrayBuffer.

5. Buffer from ArrayBuffer


node_api_create_buffer_from_arraybuffer creates a Node.js Buffer object from an existing ArrayBuffer, enabling direct binary data manipulation in JavaScript.

6. Converting C Types to JavaScript


  • napi_create_int32: Converts a C int32_t to a JavaScript number.
  • napi_create_uint32: Converts a C uint32_t to a JavaScript number.
  • napi_create_int64: Converts a C int64_t to a JavaScript number (with precision limits).
  • napi_create_double: Converts a C double to a JavaScript number.

Conclusion


By using napi_create_external and related object creation APIs, developers can safely integrate native memory and structures into JavaScript. These functions provide a powerful toolkit for building efficient, stable, and memory-safe native Addons in Node.js.

1. BigInt Creation


  • napi_create_bigint_int64: Converts a C int64_t into a JavaScript BigInt.
  • napi_create_bigint_uint64: Converts a C uint64_t into a JavaScript BigInt.
  • napi_create_bigint_words: Creates a BigInt from an array of 64-bit words, supporting very large integers.

2. String Creation


  • napi_create_string_latin1: Creates a JavaScript string from a Latin1-encoded C buffer.
  • napi_create_string_utf16: Creates a JavaScript string from a UTF-16 encoded C buffer.
  • napi_create_string_utf8: Creates a JavaScript string from a UTF-8 encoded C buffer.
  • node_api_create_external_string_latin1 / node_api_create_external_string_utf16: Creates external strings backed by native memory, with optional finalizers for cleanup.

3. Optimized Property Keys


  • node_api_create_property_key_latin1: Creates an optimized property key string using Latin1 encoding.
  • node_api_create_property_key_utf16: Creates an optimized property key string using UTF-16 encoding.
  • node_api_create_property_key_utf8: Creates an optimized property key string using UTF-8 encoding.

These optimized keys improve performance in JavaScript engines by enabling faster property lookups.

4. Array and Buffer Info


  • napi_get_array_length: Retrieves the length of a JavaScript array.
  • napi_get_arraybuffer_info: Retrieves the underlying buffer and length of an ArrayBuffer.
  • napi_get_buffer_info: Retrieves the underlying buffer and length of a Node.js Buffer or Uint8Array.

5. TypedArray and DataView Info


  • napi_get_typedarray_info: Retrieves type, length, and buffer details of a TypedArray.
  • napi_get_dataview_info: Retrieves length and buffer details of a DataView.

Conclusion


APIs such as napi_create_bigint and napi_create_string, combined with property key and buffer information functions, provide a powerful toolkit for integrating native data with JavaScript. These capabilities allow developers to build Addons that handle large integers, multiple text encodings, and efficient property access while maintaining memory safety and performance.

1. TypedArray and DataView Information


  • napi_get_typedarray_info: Retrieves type, length, buffer, and byte offset of a TypedArray.
  • napi_get_dataview_info: Retrieves length, buffer, and byte offset of a DataView.

2. Date and Primitive Values


  • napi_get_date_value: Returns the time value of a JavaScript Date as a C double.
  • napi_get_value_bool: Converts a JavaScript Boolean to a C bool.
  • napi_get_value_double: Converts a JavaScript Number to a C double.
  • napi_get_value_int32, napi_get_value_int64, napi_get_value_uint32: Convert JavaScript Numbers to C integer types.

3. BigInt Values


  • napi_get_value_bigint_int64: Converts a BigInt to a C int64_t, with lossless flag.
  • napi_get_value_bigint_uint64: Converts a BigInt to a C uint64_t, with lossless flag.
  • napi_get_value_bigint_words: Converts a BigInt into sign bit and array of 64-bit words.

4. Strings and External Values


  • napi_get_value_string_latin1: Retrieves a Latin1-encoded string.
  • napi_get_value_string_utf8: Retrieves a UTF-8 string.
  • napi_get_value_string_utf16: Retrieves a UTF-16 string.
  • napi_get_value_external: Retrieves external data pointer from a JavaScript external value.

5. Global Instances


  • napi_get_boolean: Returns the JavaScript Boolean singleton.
  • napi_get_global: Returns the global object.
  • napi_get_null: Returns the JavaScript null object.
  • napi_get_undefined: Returns the JavaScript undefined value.

6. Abstract Operations


  • napi_coerce_to_bool: Coerces a value to Boolean.
  • napi_coerce_to_number: Coerces a value to Number.
  • napi_coerce_to_object: Coerces a value to Object.
  • napi_coerce_to_string: Coerces a value to String.

7. Type Checking and Equality


  • napi_typeof: Returns the type of a JavaScript value.
  • napi_instanceof: Checks if an object is an instance of a constructor.
  • napi_is_array, napi_is_arraybuffer, napi_is_buffer, napi_is_date, napi_is_error, napi_is_typedarray, napi_is_dataview: Type checks for specific JavaScript objects.
  • napi_strict_equals: Performs strict equality comparison.

8. ArrayBuffer Management


  • napi_detach_arraybuffer: Detaches an ArrayBuffer.
  • napi_is_detached_arraybuffer: Checks if an ArrayBuffer is detached.
  • node_api_is_sharedarraybuffer: Checks if a value is a SharedArrayBuffer.

Conclusion


APIs such as napi_get_typedarray_info, napi_get_value_string_utf8, and napi_get_value_bigint_int64 provide native Addons with safe and efficient access to JavaScript values. By combining type checks, coercion functions, and buffer management, Node-API ensures that native code can interact with JavaScript objects in a way that is consistent, memory-safe, and aligned with ECMAScript semantics.

1. SharedArrayBuffer Creation


  • node_api_create_sharedarraybuffer: Creates a SharedArrayBuffer with a specified length. This buffer can be shared across multiple workers.
  • The underlying data buffer can optionally be returned to native code for direct manipulation.

2. Property Management


Node-API allows property management similar to JavaScript:

  • napi_set_property / napi_get_property: Set or retrieve a property by key.
  • napi_set_named_property / napi_get_named_property: Manage properties by string name.
  • napi_set_element / napi_get_element: Manage properties by numeric index (like arrays).
  • napi_define_properties: Efficiently define multiple properties using napi_property_descriptor.

3. Property Attributes


  • napi_writable: Property is writable.
  • napi_enumerable: Property is enumerable.
  • napi_configurable: Property is configurable.
  • napi_static: Defines static properties in classes.

4. Object Freezing and Sealing


  • napi_object_freeze: Prevents adding or modifying properties.
  • napi_object_seal: Prevents adding new properties and marks existing ones as non-configurable.

5. JavaScript Functions


  • napi_create_function: Creates a JavaScript function from native code.
  • napi_call_function: Calls a JavaScript function from native code.
  • napi_get_cb_info: Retrieves callback information such as arguments and this.
  • napi_get_new_target: Retrieves new.target in constructor calls.
  • napi_new_instance: Instantiates a new object using a constructor function.

Conclusion


By using node_api_create_sharedarraybuffer along with property and function management APIs, developers can build powerful native Addons that share data across workers and fully interact with JavaScript objects and functions. These APIs ensure efficient memory handling and seamless integration between native and JavaScript code.

1. Post Finalizer


  • node_api_post_finalizer: Schedules a napi_finalize callback asynchronously in the event loop.
  • This allows cleanup operations requiring Node-API calls to run safely outside of GC finalization.

2. Simple Asynchronous Work


  • napi_create_async_work: Creates an async work object with execute and complete callbacks.
  • napi_queue_async_work: Queues async work for execution.
  • napi_cancel_async_work: Cancels queued work before execution begins.
  • napi_delete_async_work: Frees resources associated with async work.

3. Custom Asynchronous Operations


  • napi_async_init: Initializes an async context for tracking operations.
  • napi_async_destroy: Destroys an async context to prevent leaks.
  • napi_make_callback: Calls a JavaScript function after an async operation completes.
  • napi_open_callback_scope / napi_close_callback_scope: Manage callback scopes for safe execution.

4. Version and Memory Management


  • napi_get_node_version: Retrieves Node.js version information.
  • napi_get_version: Returns the highest supported Node-API version.
  • napi_adjust_external_memory: Adjusts the amount of externally allocated memory tracked by JavaScript objects.

5. Promises


  • napi_create_promise: Creates a Promise and its associated deferred object.
  • napi_resolve_deferred: Resolves a Promise with a given value.
  • napi_reject_deferred: Rejects a Promise with a given value.
  • napi_is_promise: Checks if a value is a native Promise object.

6. Script Execution


  • napi_run_script: Executes a JavaScript string in the global scope.

7. Event Loop Access


  • napi_get_uv_event_loop: Retrieves the current libuv event loop instance.

8. Thread-Safe Function Calls


  • napi_create_threadsafe_function: Creates a thread-safe function callable from multiple threads.
  • napi_call_threadsafe_function: Queues data for invoking a JavaScript function.
  • napi_release_threadsafe_function: Releases resources associated with a thread-safe function.

Conclusion


node_api_post_finalizer and the asynchronous APIs in Node-API are essential for building robust native Addons. They enable safe cleanup, efficient async work scheduling, promise handling, and thread-safe communication between native threads and JavaScript, ensuring stability and performance in complex applications.

Written & researched by Dr. Shahin Siami