- Assertion testing
- Async hooks
- Buffer
- C++ addons
- C/C++ addons with N-API
- C++ embedder API
- Child processes
- Cluster
- Command-line options
- Console
- Crypto
- Debugger
- Deprecated APIs
- DNS
- Domain
- Errors
- Events
- File system
- Globals
- HTTP
- HTTP/2
- HTTPS
- Inspector
- Internationalization
- Modules: CommonJS modules
- Modules: ECMAScript modules
- Modules:
moduleAPI - Modules: Packages
- Net
- OS
- Path
- Performance hooks
- Policies
- Process
- Punycode
- Query strings
- Readline
- REPL
- Report
- Stream
- String decoder
- Timers
- TLS/SSL
- Trace events
- TTY
- UDP/datagram
- URL
- Utilities
- V8
- VM
- WASI
- Worker threads
- Zlib
Node.js v14.16.1 Documentation
Table of Contents
- N-API
- Implications of ABI stability
- Building
- Usage
- N-API version matrix
- Environment life cycle APIs
- Basic N-API data types
- Error handling
- Object lifetime management
- Module registration
- Working with JavaScript values
- Enum types
- Object creation functions
- Functions to convert from C types to N-API
- Functions to convert from N-API to C types
- napi_get_array_length
- napi_get_arraybuffer_info
- napi_get_buffer_info
- napi_get_prototype
- napi_get_typedarray_info
- napi_get_dataview_info
- napi_get_date_value
- napi_get_value_bool
- napi_get_value_double
- napi_get_value_bigint_int64
- napi_get_value_bigint_uint64
- napi_get_value_bigint_words
- napi_get_value_external
- napi_get_value_int32
- napi_get_value_int64
- napi_get_value_string_latin1
- napi_get_value_string_utf8
- napi_get_value_string_utf16
- napi_get_value_uint32
- Functions to get global instances
- Working with JavaScript values and abstract operations
- Working with JavaScript properties
- Structures
- Functions
- napi_get_property_names
- napi_get_all_property_names
- napi_set_property
- napi_get_property
- napi_has_property
- napi_delete_property
- napi_has_own_property
- napi_set_named_property
- napi_get_named_property
- napi_has_named_property
- napi_set_element
- napi_get_element
- napi_has_element
- napi_delete_element
- napi_define_properties
- napi_object_freeze
- napi_object_seal
- Working with JavaScript functions
- Object wrap
- Simple asynchronous operations
- Custom asynchronous operations
- Version management
- Memory management
- Promises
- Script execution
- libuv event loop
- Asynchronous thread-safe function calls
- Calling a thread-safe function
- Reference counting of thread-safe functions
- Deciding whether to keep the process running
- napi_create_threadsafe_function
- napi_get_threadsafe_function_context
- napi_call_threadsafe_function
- napi_acquire_threadsafe_function
- napi_release_threadsafe_function
- napi_ref_threadsafe_function
- napi_unref_threadsafe_function
N-API#
N-API (pronounced N as in the letter, followed by API) is an API for building native Addons. It is independent from the underlying JavaScript runtime (for example, V8) and is maintained as part of Node.js itself. This API will be Application Binary Interface (ABI) stable across versions of Node.js. It is intended to insulate Addons from changes in the underlying JavaScript engine and allow modules compiled for one major version to run on later major versions of Node.js without recompilation. The ABI Stability guide provides a more in-depth explanation.
Addons are built/packaged with the same approach/tools outlined in the section titled C++ Addons. The only difference is the set of APIs that are used by the native code. Instead of using the V8 or Native Abstractions for Node.js APIs, the functions available in the N-API are used.
APIs exposed by N-API are generally used to create and manipulate JavaScript values. Concepts and operations generally map to ideas specified in the ECMA-262 Language Specification. The APIs have the following properties:
- All N-API calls return a status code of type
napi_status. This status indicates whether the API call succeeded or failed. - The API's return value is passed via an out parameter.
- All JavaScript values are abstracted behind an opaque type named
napi_value. - In case of an error status code, additional information can be obtained
using
napi_get_last_error_info. More information can be found in the error handling section Error handling.
The N-API is a C API that ensures ABI stability across Node.js versions
and different compiler levels. A C++ API can be easier to use.
To support using C++, the project maintains a
C++ wrapper module called node-addon-api.
This wrapper provides an inlineable C++ API. Binaries built
with node-addon-api will depend on the symbols for the N-API C-based
functions exported by Node.js. node-addon-api is a more
efficient way to write code that calls N-API. Take, for example, the
following node-addon-api code. The first section shows the
node-addon-api code and the second section shows what actually gets
used in the addon.
Object obj = Object::New(env);
obj["foo"] = String::New(env, "bar");
napi_status status;
napi_value object, string;
status = napi_create_object(env, &object);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
status = napi_create_string_utf8(env, "bar", NAPI_AUTO_LENGTH, &string);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
status = napi_set_named_property(env, object, "foo", string);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
The end result is that the addon only uses the exported C APIs. As a result, it still gets the benefits of the ABI stability provided by the C API.
When using node-addon-api instead of the C APIs, start with the API docs
for node-addon-api.
The N-API Resource offers an
excellent orientation and tips for developers just getting started with N-API
and node-addon-api.
Implications of ABI stability#
Although N-API provides an ABI stability guarantee, other parts of Node.js do not, and any external libraries used from the addon may not. In particular, none of the following APIs provide an ABI stability guarantee across major versions:
-
the Node.js C++ APIs available via any of
#include <node.h> #include <node_buffer.h> #include <node_version.h> #include <node_object_wrap.h> -
the libuv APIs which are also included with Node.js and available via
#include <uv.h> -
the V8 API available via
#include <v8.h>
Thus, for an addon to remain ABI-compatible across Node.js major versions, it must use N-API exclusively by restricting itself to using
#include <node_api.h>
and by checking, for all external libraries that it uses, that the external library makes ABI stability guarantees similar to N-API.
Building#
Unlike modules written in JavaScript, developing and deploying Node.js native addons using N-API requires an additional set of tools. Besides the basic tools required to develop for Node.js, the native addon developer requires a toolchain that can compile C and C++ code into a binary. In addition, depending upon how the native addon is deployed, the user of the native addon will also need to have a C/C++ toolchain installed.
For Linux developers, the necessary C/C++ toolchain packages are readily available. GCC is widely used in the Node.js community to build and test across a variety of platforms. For many developers, the LLVM compiler infrastructure is also a good choice.
For Mac developers, Xcode offers all the required compiler tools. However, it is not necessary to install the entire Xcode IDE. The following command installs the necessary toolchain:
xcode-select --install
For Windows developers, Visual Studio offers all the required compiler tools. However, it is not necessary to install the entire Visual Studio IDE. The following command installs the necessary toolchain:
npm install --global windows-build-tools
The sections below describe the additional tools available for developing and deploying Node.js native addons.
Build tools#
Both the tools listed here require that users of the native addon have a C/C++ toolchain installed in order to successfully install the native addon.
node-gyp#
node-gyp is a build system based on Google's GYP tool and comes bundled with npm. GYP, and therefore node-gyp, requires that Python be installed.
Historically, node-gyp has been the tool of choice for building native addons. It has widespread adoption and documentation. However, some developers have run into limitations in node-gyp.
CMake.js#
CMake.js is an alternative build system based on CMake.
CMake.js is a good choice for projects that already use CMake or for developers affected by limitations in node-gyp.
Uploading precompiled binaries#
The three tools listed here permit native addon developers and maintainers to create and upload binaries to public or private servers. These tools are typically integrated with CI/CD build systems like Travis CI and AppVeyor to build and upload binaries for a variety of platforms and architectures. These binaries are then available for download by users who do not need to have a C/C++ toolchain installed.
node-pre-gyp#
node-pre-gyp is a tool based on node-gyp that adds the ability to upload binaries to a server of the developer's choice. node-pre-gyp has particularly good support for uploading binaries to Amazon S3.
prebuild#
prebuild is a tool that supports builds using either node-gyp or CMake.js. Unlike node-pre-gyp which supports a variety of servers, prebuild uploads binaries only to GitHub releases. prebuild is a good choice for GitHub projects using CMake.js.
prebuildify#
prebuildify is a tool based on node-gyp. The advantage of prebuildify is that the built binaries are bundled with the native module when it's uploaded to npm. The binaries are downloaded from npm and are immediately available to the module user when the native module is installed.
Usage#
In order to use the N-API functions, include the file node_api.h which is
located in the src directory in the node development tree:
#include <node_api.h>
This will opt into the default NAPI_VERSION for the given release of Node.js.
In order to ensure compatibility with specific versions of N-API, the version
can be specified explicitly when including the header:
#define NAPI_VERSION 3
#include <node_api.h>
This restricts the N-API surface to just the functionality that was available in the specified (and earlier) versions.
Some of the N-API surface is experimental and requires explicit opt-in:
#define NAPI_EXPERIMENTAL
#include <node_api.h>
In this case the entire API surface, including any experimental APIs, will be available to the module code.
N-API version matrix#
N-API versions are additive and versioned independently from Node.js. Version 4 is an extension to version 3 in that it has all of the APIs from version 3 with some additions. This means that it is not necessary to recompile for new versions of Node.js which are listed as supporting a later version.
| 1 | 2 | 3 | |
|---|---|---|---|
| v6.x | v6.14.2* | ||
| v8.x | v8.6.0** | v8.10.0* | v8.11.2 |
| v9.x | v9.0.0* | v9.3.0* | v9.11.0* |
| ≥ v10.x | all releases | all releases | all releases |
| 4 | 5 | 6 | 7 | |
|---|---|---|---|---|
| v10.x | v10.16.0 | v10.17.0 | v10.20.0 | |
| v11.x | v11.8.0 | |||
| v12.x | v12.0.0 | v12.11.0 | v12.17.0 | v12.19.0 |
| v13.x | v13.0.0 | v13.0.0 | ||
| v14.x | v14.0.0 | v14.0.0 | v14.0.0 | v14.12.0 |
* N-API was experimental.
** Node.js 8.0.0 included N-API as experimental. It was released as N-API version 1 but continued to evolve until Node.js 8.6.0. The API is different in versions prior to Node.js 8.6.0. We recommend N-API version 3 or later.
Each API documented for N-API will have a header named added in:, and APIs
which are stable will have the additional header N-API version:.
APIs are directly usable when using a Node.js version which supports
the N-API version shown in N-API version: or higher.
When using a Node.js version that does not support the
N-API version: listed or if there is no N-API version: listed,
then the API will only be available if
#define NAPI_EXPERIMENTAL precedes the inclusion of node_api.h
or js_native_api.h. If an API appears not to be available on
a version of Node.js which is later than the one shown in added in: then
this is most likely the reason for the apparent absence.
The N-APIs associated strictly with accessing ECMAScript features from native
code can be found separately in js_native_api.h and js_native_api_types.h.
The APIs defined in these headers are included in node_api.h and
node_api_types.h. The headers are structured in this way in order to allow
implementations of N-API outside of Node.js. For those implementations the
Node.js specific APIs may not be applicable.
The Node.js-specific parts of an addon can be separated from the code that
exposes the actual functionality to the JavaScript environment so that the
latter may be used with multiple implementations of N-API. In the example below,
addon.c and addon.h refer only to js_native_api.h. This ensures that
addon.c can be reused to compile against either the Node.js implementation of
N-API or any implementation of N-API outside of Node.js.
addon_node.c is a separate file that contains the Node.js specific entry point
to the addon and which instantiates the addon by calling into addon.c when the
addon is loaded into a Node.js environment.
// addon.h
#ifndef _ADDON_H_
#define _ADDON_H_
#include <js_native_api.h>
napi_value create_addon(napi_env env);
#endif // _ADDON_H_
// addon.c
#include "addon.h"
#define NAPI_CALL(env, call) \
do { \
napi_status status = (call); \
if (status != napi_ok) { \
const napi_extended_error_info* error_info = NULL; \
napi_get_last_error_info((env), &error_info); \
bool is_pending; \
napi_is_exception_pending((env), &is_pending); \
if (!is_pending) { \
const char* message = (error_info->error_message == NULL) \
? "empty error message" \
: error_info->error_message; \
napi_throw_error((env), NULL, message); \
return NULL; \
} \
} \
} while(0)
static napi_value
DoSomethingUseful(napi_env env, napi_callback_info info) {
// Do something useful.
return NULL;
}
napi_value create_addon(napi_env env) {
napi_value result;
NAPI_CALL(env, napi_create_object(env, &result));
napi_value exported_function;
NAPI_CALL(env, napi_create_function(env,
"doSomethingUseful",
NAPI_AUTO_LENGTH,
DoSomethingUseful,
NULL,
&exported_function));
NAPI_CALL(env, napi_set_named_property(env,
result,
"doSomethingUseful",
exported_function));
return result;
}
// addon_node.c
#include <node_api.h>
#include "addon.h"
NAPI_MODULE_INIT() {
// This function body is expected to return a `napi_value`.
// The variables `napi_env env` and `napi_value exports` may be used within
// the body, as they are provided by the definition of `NAPI_MODULE_INIT()`.
return create_addon(env);
}
Environment life cycle APIs#
Section 8.7 of the ECMAScript Language Specification defines the concept of an "Agent" as a self-contained environment in which JavaScript code runs. Multiple such Agents may be started and terminated either concurrently or in sequence by the process.
A Node.js environment corresponds to an ECMAScript Agent. In the main process, an environment is created at startup, and additional environments can be created on separate threads to serve as worker threads. When Node.js is embedded in another application, the main thread of the application may also construct and destroy a Node.js environment multiple times during the life cycle of the application process such that each Node.js environment created by the application may, in turn, during its life cycle create and destroy additional environments as worker threads.
From the perspective of a native addon this means that the bindings it provides may be called multiple times, from multiple contexts, and even concurrently from multiple threads.
Native addons may need to allocate global state which they use during their entire life cycle such that the state must be unique to each instance of the addon.
To this end, N-API provides a way to allocate data such that its life cycle is tied to the life cycle of the Agent.
napi_set_instance_data#
napi_status napi_set_instance_data(napi_env env,
void* data,
napi_finalize finalize_cb,
void* finalize_hint);
[in] env: The environment that the N-API call is invoked under.[in] data: The data item to make available to bindings of this instance.[in] finalize_cb: The function to call when the environment is being torn down. The function receivesdataso that it might free it.napi_finalizeprovides more details.[in] finalize_hint: Optional hint to pass to the finalize callback during collection.
Returns napi_ok if the API succeeded.
This API associates data with the currently running Agent. data can later
be retrieved using napi_get_instance_data(). Any existing data associated with
the currently running Agent which was set by means of a previous call to
napi_set_instance_data() will be overwritten. If a finalize_cb was provided
by the previous call, it will not be called.
napi_get_instance_data#
napi_status napi_get_instance_data(napi_env env,
void** data);
[in] env: The environment that the N-API call is invoked under.[out] data: The data item that was previously associated with the currently running Agent by a call tonapi_set_instance_data().
Returns napi_ok if the API succeeded.
This API retrieves data that was previously associated with the currently
running Agent via napi_set_instance_data(). If no data is set, the call will
succeed and data will be set to NULL.
Basic N-API data types#
N-API exposes the following fundamental datatypes as abstractions that are consumed by the various APIs. These APIs should be treated as opaque, introspectable only with other N-API calls.
napi_status#
Integral status code indicating the success or failure of a N-API call. Currently, the following status codes are supported.
typedef enum {
napi_ok,
napi_invalid_arg,
napi_object_expected,
napi_string_expected,
napi_name_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_handle_scope_mismatch,
napi_callback_scope_mismatch,
napi_queue_full,
napi_closing,
napi_bigint_expected,
napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
napi_would_deadlock, /* unused */
} napi_status;
If additional information is required upon an API returning a failed status,
it can be obtained by calling napi_get_last_error_info.
napi_extended_error_info#
typedef struct {
const char* error_message;
void* engine_reserved;
uint32_t engine_error_code;
napi_status error_code;
} napi_extended_error_info;
error_message: UTF8-encoded string containing a VM-neutral description of the error.engine_reserved: Reserved for VM-specific error details. This is currently not implemented for any VM.engine_error_code: VM-specific error code. This is currently not implemented for any VM.error_code: The N-API status code that originated with the last error.
See the Error handling section for additional information.
napi_env#
napi_env is used to represent a context that the underlying N-API
implementation can use to persist VM-specific state. This structure is passed
to native functions when they're invoked, and it must be passed back when
making N-API calls. Specifically, the same napi_env that was passed in when
the initial native function was called must be passed to any subsequent
nested N-API calls. Caching the napi_env for the purpose of general reuse,
and passing the napi_env between instances of the same addon running on
different Worker threads is not allowed. The napi_env becomes invalid
when an instance of a native addon is unloaded. Notification of this event is
delivered through the callbacks given to napi_add_env_cleanup_hook and
napi_set_instance_data.
napi_value#
This is an opaque pointer that is used to represent a JavaScript value.
napi_threadsafe_function#
This is an opaque pointer that represents a JavaScript function which can be
called asynchronously from multiple threads via
napi_call_threadsafe_function().
napi_threadsafe_function_release_mode#
A value to be given to napi_release_threadsafe_function() to indicate whether
the thread-safe function is to be closed immediately (napi_tsfn_abort) or
merely released (napi_tsfn_release) and thus available for subsequent use via
napi_acquire_threadsafe_function() and napi_call_threadsafe_function().
typedef enum {
napi_tsfn_release,
napi_tsfn_abort
} napi_threadsafe_function_release_mode;
napi_threadsafe_function_call_mode#
A value to be given to napi_call_threadsafe_function() to indicate whether
the call should block whenever the queue associated with the thread-safe
function is full.
typedef enum {
napi_tsfn_nonblocking,
napi_tsfn_blocking
} napi_threadsafe_function_call_mode;
N-API memory management types#
napi_handle_scope#
This is an abstraction used to control and modify the lifetime of objects created within a particular scope. In general, N-API values are created within the context of a handle scope. When a native method is called from JavaScript, a default handle scope will exist. If the user does not explicitly create a new handle scope, N-API values will be created in the default handle scope. For any invocations of code outside the execution of a native method (for instance, during a libuv callback invocation), the module is required to create a scope before invoking any functions that can result in the creation of JavaScript values.
Handle scopes are created using napi_open_handle_scope and are destroyed
using napi_close_handle_scope. Closing the scope can indicate to the GC
that all napi_values created during the lifetime of the handle scope are no
longer referenced from the current stack frame.
For more details, review the Object lifetime management.
napi_escapable_handle_scope#
Escapable handle scopes are a special type of handle scope to return values created within a particular handle scope to a parent scope.
napi_ref#
This is the abstraction to use to reference a napi_value. This allows for
users to manage the lifetimes of JavaScript values, including defining their
minimum lifetimes explicitly.
For more details, review the Object lifetime management.
napi_type_tag#
A 128-bit value stored as two unsigned 64-bit integers. It serves as a UUID
with which JavaScript objects can be "tagged" in order to ensure that they are
of a certain type. This is a stronger check than napi_instanceof, because
the latter can report a false positive if the object's prototype has been
manipulated. Type-tagging is most useful in conjunction with napi_wrap
because it ensures that the pointer retrieved from a wrapped object can be
safely cast to the native type corresponding to the type tag that had been
previously applied to the JavaScript object.
typedef struct {
uint64_t lower;
uint64_t upper;
} napi_type_tag;
napi_async_cleanup_hook_handle#
An opaque value returned by napi_add_async_cleanup_hook. It must be passed
to napi_remove_async_cleanup_hook when the chain of asynchronous cleanup
events completes.
N-API callback types#
napi_callback_info#
Opaque datatype that is passed to a callback function. It can be used for getting additional information about the context in which the callback was invoked.
napi_callback#
Function pointer type for user-provided native functions which are to be exposed to JavaScript via N-API. Callback functions should satisfy the following signature:
typedef napi_value (*napi_callback)(napi_env, napi_callback_info);
Unless for reasons discussed in Object Lifetime Management, creating a
handle and/or callback scope inside a napi_callback is not necessary.
napi_finalize#
Function pointer type for add-on provided functions that allow the user to be
notified when externally-owned data is ready to be cleaned up because the
object with which it was associated with, has been garbage-collected. The user
must provide a function satisfying the following signature which would get
called upon the object's collection. Currently, napi_finalize can be used for
finding out when objects that have external data are collected.
typedef void (*napi_finalize)(napi_env env,
void* finalize_data,
void* finalize_hint);
Unless for reasons discussed in Object Lifetime Management, creating a handle and/or callback scope inside the function body is not necessary.
napi_async_execute_callback#
Function pointer used with functions that support asynchronous operations. Callback functions must satisfy the following signature:
typedef void (*napi_async_execute_callback)(napi_env env, void* data);
Implementations of this function must avoid making N-API calls that execute
JavaScript or interact with JavaScript objects. N-API calls should be in the
napi_async_complete_callback instead. Do not use the napi_env parameter as
it will likely result in execution of JavaScript.