Appearance
Workflow: Module Load Lifecycle
Fresh 🌱What actually happens from the moment Node loads your native module to the moment a Rust-backed function returns a value.
The flow
sequenceDiagram
participant JS as Node.js
participant NODE as index.node
participant MAIN as "#[neon::main] main()"
participant FN as Your Rust fn
JS->>NODE: require('.')
NODE->>MAIN: load module, run init (once)
MAIN->>MAIN: cx.export_function("get", get_fn)
MAIN->>MAIN: neon::registered().export(cx)
MAIN-->>JS: module.exports populated
JS->>FN: addon.get(args)
FN->>FN: read args via cx, build JS values
FN-->>JS: Ok(value) or thrown exceptionStage by stage
require('.')- Node loads the compiledindex.nodebinary, exactly like loading any other module, but the file is native code.- Module initialization runs once - Neon calls the function marked
#[neon::main]. This is the only code that runs at load time. - Exports are registered - inside
main, you callcx.export_function(...)for explicit exports and/orneon::registered().export(&mut cx)?to publish everything tagged with#[neon::export]. You can alsocx.export_value(...)for constants and prebuilt objects. module.exportsis populated - oncemainreturnsOk(()), the JavaScript side sees a fully formed exports object.- A call arrives - when JS invokes an exported function, Neon creates a fresh
FunctionContextand runs your Rust function. - The function returns - your function reads arguments through
cx, builds JS values throughcx, and returns aJsResult: eitherOk(value)(returned to JS) orErr(...)(thrown as a JS exception).
Key facts
| Fact | Why it matters |
|---|---|
#[neon::main] runs once, at load | Do one-time setup here (register exports, build constant objects). Do not put per-call work here. |
Each call gets its own FunctionContext | Contexts are not shared or reused across calls; never store one. |
The init function returns NeonResult | Export registration can throw, so propagate with ?. |
Mapping back to code
This whole diagram is driven by two things you write: the #[neon::main] function (step 2-4) and your individual #[neon::export] / FunctionContext functions (step 5-6). See the Export Functions SOP.