Skip to content

Implement Node-API in bun.js (napi) #158

@Jarred-Sumner

Description

@Jarred-Sumner

Node-API is Node.js' native addon API. Bun implements Node-API so that native addons built for Node.js work in Bun without modification or recompilation.

If a native addon crashes or misbehaves in Bun, please open a new issue with a reproduction rather than commenting here.

Status: API surface complete

Every napi_* and node_api_* function is implemented and exported. Bun runs Node.js' own js-native-api and node-api test suites in CI on every commit (see test/napi/node-napi-tests/).

Suite Pass Todo %
js-native-api (engine-agnostic core) 53 0 100%
node-api (Node.js-runtime-specific) 21 23 47.7%
Combined 74 23 76.3%

Counted on Linux. macOS/Windows each have one extra platform-specific todo (73/97, 75.3%).

The node-api todos are concentrated in async_hooks integration, uv_* loop/threadpool semantics, worker-terminate finalization, and fatal-error reporting — see the todoIf entries in test/napi/node-napi-tests/test/node-api/*/do.test.ts for the live list.

Remaining work is behavioral parity in those areas and edge-case compatibility with specific packages, not missing API surface.

Implementation

Where What
src/bun.js/bindings/napi.cpp Most napi_* functions, JSC integration
src/napi/napi.zig Threadsafe functions, async work, event loop, handle scopes
src/bun.js/bindings/v8/ V8 C++ API shim (for addons that bypass N-API)
src/symbols.txt Exported symbol list

Known gaps & caveats

  • async_hooks integrationnapi_async_init, napi_async_destroy, napi_make_callback, napi_open_callback_scope, and napi_close_callback_scope all work, but do not emit async_hooks lifecycle events. We don't plan to implement this. Node.js itself marks async_hooks as Experimental and discourages its use: "Please migrate away from this API, if you can. We do not recommend using the createHook, AsyncHook, and executionAsyncResource APIs as they have usability issues, safety risks, and performance implications." Bun implements the stable AsyncLocalStorage API instead, which is what Node recommends migrating to.
  • libuv — a subset of uv_* symbols is exported for addons that link against libuv directly. On Linux/macOS, Bun does not run on libuv, so uv_default_loop() is not the runtime's event loop — addons must use napi_get_uv_event_loop (N-API addons using uv_default_loop for uv_async don’t fire callbacks; using napi_get_uv_event_loop fixes it #23192). We don't currently plan to implement all of libuv inside Bun, but we may revisit if enough bug reports show it's needed in practice — tracked in Implement libuv functions #18546.
  • Worker termination — finalizer and buffer-callback ordering during Worker.terminate() doesn't fully match Node. Tracked as part of Worker & worker_threads stability tracking issue #15964 alongside other worker_threads stability work.
  • napi_adjust_external_memory reports to JSC's GC heuristic but does not behave identically to V8.
Full function list — 156/156 implemented

napi_*

  • napi_acquire_threadsafe_function
  • napi_add_async_cleanup_hook
  • napi_add_env_cleanup_hook
  • napi_add_finalizer
  • napi_adjust_external_memory
  • napi_async_destroy
  • napi_async_init
  • napi_call_function
  • napi_call_threadsafe_function
  • napi_cancel_async_work
  • napi_check_object_type_tag
  • napi_close_callback_scope
  • napi_close_escapable_handle_scope
  • napi_close_handle_scope
  • napi_coerce_to_bool
  • napi_coerce_to_number
  • napi_coerce_to_object
  • napi_coerce_to_string
  • napi_create_array
  • napi_create_array_with_length
  • napi_create_arraybuffer
  • napi_create_async_work
  • napi_create_bigint_int64
  • napi_create_bigint_uint64
  • napi_create_bigint_words
  • napi_create_buffer
  • napi_create_buffer_copy
  • napi_create_dataview
  • napi_create_date
  • napi_create_double
  • napi_create_error
  • napi_create_external
  • napi_create_external_arraybuffer
  • napi_create_external_buffer
  • napi_create_function
  • napi_create_int32
  • napi_create_int64
  • napi_create_object
  • napi_create_promise
  • napi_create_range_error
  • napi_create_reference
  • napi_create_string_latin1
  • napi_create_string_utf16
  • napi_create_string_utf8
  • napi_create_symbol
  • napi_create_threadsafe_function
  • napi_create_type_error
  • napi_create_typedarray
  • napi_create_uint32
  • napi_define_class
  • napi_define_properties
  • napi_delete_async_work
  • napi_delete_element
  • napi_delete_property
  • napi_delete_reference
  • napi_detach_arraybuffer
  • napi_escape_handle
  • napi_fatal_error
  • napi_fatal_exception
  • napi_get_all_property_names
  • napi_get_and_clear_last_exception
  • napi_get_array_length
  • napi_get_arraybuffer_info
  • napi_get_boolean
  • napi_get_buffer_info
  • napi_get_cb_info
  • napi_get_dataview_info
  • napi_get_date_value
  • napi_get_element
  • napi_get_global
  • napi_get_instance_data
  • napi_get_last_error_info
  • napi_get_named_property
  • napi_get_new_target
  • napi_get_node_version
  • napi_get_null
  • napi_get_property
  • napi_get_property_names
  • napi_get_prototype
  • napi_get_reference_value
  • napi_get_threadsafe_function_context
  • napi_get_typedarray_info
  • napi_get_undefined
  • napi_get_uv_event_loop
  • napi_get_value_bigint_int64
  • napi_get_value_bigint_uint64
  • napi_get_value_bigint_words
  • napi_get_value_bool
  • napi_get_value_double
  • napi_get_value_external
  • napi_get_value_int32
  • napi_get_value_int64
  • napi_get_value_string_latin1
  • napi_get_value_string_utf16
  • napi_get_value_string_utf8
  • napi_get_value_uint32
  • napi_get_version
  • napi_has_element
  • napi_has_named_property
  • napi_has_own_property
  • napi_has_property
  • napi_instanceof
  • napi_is_array
  • napi_is_arraybuffer
  • napi_is_buffer
  • napi_is_dataview
  • napi_is_date
  • napi_is_detached_arraybuffer
  • napi_is_error
  • napi_is_exception_pending
  • napi_is_promise
  • napi_is_typedarray
  • napi_make_callback
  • napi_module_register
  • napi_new_instance
  • napi_object_freeze
  • napi_object_seal
  • napi_open_callback_scope
  • napi_open_escapable_handle_scope
  • napi_open_handle_scope
  • napi_queue_async_work
  • napi_ref_threadsafe_function
  • napi_reference_ref
  • napi_reference_unref
  • napi_reject_deferred
  • napi_release_threadsafe_function
  • napi_remove_async_cleanup_hook
  • napi_remove_env_cleanup_hook
  • napi_remove_wrap
  • napi_resolve_deferred
  • napi_run_script
  • napi_set_element
  • napi_set_instance_data
  • napi_set_named_property
  • napi_set_property
  • napi_strict_equals
  • napi_throw
  • napi_throw_error
  • napi_throw_range_error
  • napi_throw_type_error
  • napi_type_tag_object
  • napi_typeof
  • napi_unref_threadsafe_function
  • napi_unwrap
  • napi_wrap

node_api_*

  • node_api_create_buffer_from_arraybuffer
  • node_api_create_external_string_latin1
  • node_api_create_external_string_utf16
  • node_api_create_property_key_latin1
  • node_api_create_property_key_utf16
  • node_api_create_property_key_utf8
  • node_api_create_syntax_error
  • node_api_get_module_file_name
  • node_api_post_finalizer
  • node_api_symbol_for
  • node_api_throw_syntax_error

Related tracking

Metadata

Metadata

Assignees

No one assigned

    Labels

    trackingAn umbrella issue for tracking big features

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions