#3341·napi-rs

Feat: Explicit Resource Management support -> Symbol bindings

Author: H-Plus-TimeCreated Jun 19, 2026Updated Jun 19, 2026

See the tc39 proposal doc for motivations/background: https://github.com/tc39/proposal-explicit-resource-management.

Essentially that proposal (amongst other things) allows you to do:

javascript
{
  using thing = new FooService();
  thing.useABunchOfMemory();
}
// immediately trigger free/drop/finalize/close on FooService

This is mediated through Symbol.dispose, a la:

javascript
class FooService {
  [Symbol.dispose]() {
    this.free();
  }
}

The node maintainers are working their way through the core resource-like classes/interfaces (e.g. sqlite) adding dispose markers, and wasm-bindgen recently switched to including it on all bound structs (a surprise to me, it was behind a flag when I added it a couple of years ago).

The main blocker is the inability to use well-known Symbols as the name for a binding. It looks like it can only be done during napi_register_module_v1 (by which point we have the napi_env, but have not yet called napi_define_class - right there is where we can null out the utf8name and set name to the relevant Symbol (well-known symbols being direct properties of the globalThis.Symbol function).

The other well-knowns (barring asyncIterator, that starts from Node 10, N-API 3) appear to have all been around since N-API's inception (their nonexistence on the Symbol global will never be an issue). This, asyncDispose, asyncIterator, and any future well-knowns... I'd be interested to hear maintainers' opinions on this - when the symbol does not exist, do you a. leave the property name verbatim or b. produce a fixed convention Symbol via Symbol.for(<variation on the symbol name>)?