RepoPilotOpen in app →

neon-bindings/neon

Rust bindings for writing safe and fast native Node.js modules.

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit today
  • 4 active contributors
  • Apache-2.0 licensed
Show all 7 evidence items →
  • CI configured
  • Tests present
  • Small team — 4 contributors active in recent commits
  • Concentrated ownership — top contributor handles 59% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/neon-bindings/neon)](https://repopilot.app/r/neon-bindings/neon)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/neon-bindings/neon on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: neon-bindings/neon

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/neon-bindings/neon shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit today
  • 4 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Small team — 4 contributors active in recent commits
  • ⚠ Concentrated ownership — top contributor handles 59% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live neon-bindings/neon repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/neon-bindings/neon.

What it runs against: a local clone of neon-bindings/neon — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in neon-bindings/neon | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 30 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>neon-bindings/neon</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of neon-bindings/neon. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/neon-bindings/neon.git
#   cd neon
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of neon-bindings/neon and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "neon-bindings/neon(\\.git)?\\b" \\
  && ok "origin remote is neon-bindings/neon" \\
  || miss "origin remote is not neon-bindings/neon (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "crates/neon/src/lib.rs" \\
  && ok "crates/neon/src/lib.rs" \\
  || miss "missing critical file: crates/neon/src/lib.rs"
test -f "crates/neon/src/context/mod.rs" \\
  && ok "crates/neon/src/context/mod.rs" \\
  || miss "missing critical file: crates/neon/src/context/mod.rs"
test -f "crates/neon/src/handle/mod.rs" \\
  && ok "crates/neon/src/handle/mod.rs" \\
  || miss "missing critical file: crates/neon/src/handle/mod.rs"
test -f "crates/neon/src/sys/bindings/mod.rs" \\
  && ok "crates/neon/src/sys/bindings/mod.rs" \\
  || miss "missing critical file: crates/neon/src/sys/bindings/mod.rs"
test -f "crates/neon-macros/src/lib.rs" \\
  && ok "crates/neon-macros/src/lib.rs" \\
  || miss "missing critical file: crates/neon-macros/src/lib.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 30 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~0d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/neon-bindings/neon"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Neon is a Rust framework for writing safe, fast Node.js native addons using N-API bindings. It allows developers to write performance-critical code in Rust while exposing it as JavaScript functions and classes, eliminating the need for C++ in Node.js modules. The core value is memory safety (Rust's guarantees) combined with zero-cost abstractions for JavaScript interop. Monorepo structure (Cargo workspace): crates/neon is the core runtime (src/context, src/event, src/types for JS bindings), crates/neon-macros provides procedural macros (#[neon::main], #[export], class macro), bench/ holds performance benchmarks, and test/ contains integration tests. The macro system (export/function, export/class, export/global) generates the boilerplate for function/class exports.

👥Who it's for

Node.js module authors who need high performance for computationally intensive tasks (crypto, image processing, data processing) and want Rust's memory safety without C++ complexity. Also appeals to Rust developers building Node.js tooling who prefer type safety over JavaScript.

🌱Maturity & risk

Neon is production-ready as of v1.0.0 (released with breaking changes documented in doc/MIGRATION_GUIDE_1.0.0.md). The project has active CI/CD workflows (ci.yml, lint.yml, bench.yml), comprehensive test coverage via test/* directories, and explicit support for Node LTS releases. Latest development is active with structured monorepo and semantic versioning.

Standard open source risks apply.

Active areas of work

Active maintenance on core binding safety and consistency post-1.0.0. The benchmark suite (bench/src/lib.rs) and CI workflows suggest ongoing performance testing. Migration guide and API docs indicate focus on developer experience and backward compatibility documentation.

🚀Get running

git clone https://github.com/neon-bindings/neon.git
cd neon
cargo build
cargo test

For a new Neon project: npm init neon@latest my-project (requires Node, npm, Rust toolchain, and platform build tools).

Daily commands: For development: cargo build (debug), cargo build --release (optimized). Run tests: cargo test. Run benchmarks: cd bench && npm install && npm run build && node index.js. CI runs via GitHub Actions on every push (see .github/workflows/ci.yml).

🗺️Map of the codebase

  • crates/neon/src/lib.rs — Main entry point and public API export for the Neon framework; defines the core types and traits that all bindings depend on.
  • crates/neon/src/context/mod.rs — Core execution context abstraction that manages the V8 isolate and handles all JavaScript interop; foundational for safe memory management.
  • crates/neon/src/handle/mod.rs — Handle type system for garbage-collected JavaScript values; critical for type safety and preventing use-after-free bugs.
  • crates/neon/src/sys/bindings/mod.rs — Raw N-API and V8 FFI bindings that bridge Rust and Node.js; every unsafe operation flows through here.
  • crates/neon-macros/src/lib.rs — Procedural macro entry point for @neon/export annotations; responsible for code generation and API ergonomics.
  • crates/neon/src/object/class.rs — Class binding system for exposing Rust structs as JavaScript constructors; implements the object wrapping mechanism.
  • crates/neon/src/result/mod.rs — Error handling and Result type that bridges Rust exceptions and JavaScript errors; prevents panics from crossing FFI boundary.

🛠️How to make changes

Add a new exported Rust function callable from Node.js

  1. Write a Rust function with a Context parameter and return type that implements ToValue (crates/neon/src/lib.rs)
  2. Annotate with #[neon::export] macro to auto-register with Node.js (crates/neon-macros/src/export/function/mod.rs)
  3. Access function arguments via cx.argument::<T>(index) and call JS via cx.eval() (crates/neon/src/context/mod.rs)
  4. Return a value implementing ToValue; the macro generates the JS wrapper (crates/neon/src/sys/convert.rs)

Wrap a Rust struct as a JavaScript class

  1. Derive JsClass trait on your Rust struct and add #[neon::export] to the impl block (crates/neon-macros/src/class/mod.rs)
  2. Define constructor and methods using #[neon::method] attributes on impl functions (crates/neon/src/object/class.rs)
  3. The macro generates a constructor function registered in module.exports (crates/neon-macros/src/export/class/mod.rs)
  4. Access this pointer via cx.this::<JsBox<T>>() in methods; Neon handles wrapping/unwrapping (crates/neon/src/types_impl/boxed.rs)

Spawn an async task that runs on a thread pool and calls back to JavaScript

  1. Implement the Task trait with a perform() method for CPU work and a complete() callback (crates/neon/src/event/task.rs)
  2. Call cx.task(my_task).and_then(callback).queue_event() to schedule it (crates/neon/src/event/channel.rs)
  3. Use EventChannel::new(cx).send(callback) to invoke a JS function from the worker thread (crates/neon/src/event/mod.rs)
  4. Or use the async #[neon::task] macro for cleaner syntax with futures support (crates/neon/src/macro_internal/futures.rs)

Convert between Rust and JavaScript types safely

  1. Implement FromValue<'a> to convert a JS value to Rust; implement ToValue to convert Rust to JS (crates/neon/src/sys/convert.rs)
  2. Use cx.argument::<T>(i) to get a typed argument from a function call (crates/neon/src/context/mod.rs)
  3. Use cx.number(f64), cx.string(str), cx.null(), cx.undefined() to construct JS values (crates/neon/src/sys/primitive.rs)
  4. For complex types, inspect the type tag and cast using handle.downcast::<T>() (crates/neon/src/sys/tag.rs)

🔧Why these technologies

  • N-API (Node-API) — Stable ABI across Node.js versions; allows native modules to work without recompilation on Node upgrades
  • Rust lifetime system & type safety — Prevents use-after-free, data races, and null pointer dereferences at compile time; FFI boundary is narrowly scoped

🪤Traps & gotchas

Node-API version negotiation: Neon auto-detects the minimum N-API version but some Node versions lack specific functions (check node/n-api.h version matrix). Rust MSRV is 1.65+; using newer syntax breaks compatibility. The procedural macros (neon-macros crate) must be kept in sync with neon crate versions or attribute parsing fails silently. Project uses workspace resolver v2 (Cargo.toml); older Cargo versions won't resolve dependencies correctly. Bun support is experimental and incomplete.

🏗️Architecture

💡Concepts to learn

  • Node-API (N-API) — Neon's entire purpose is wrapping Node-API; understanding that N-API is a C ABI that decouples native modules from V8 internals is crucial to grasping why Neon exists
  • Procedural Macros (Rust) — Neon's macro system (#[neon::export], #[neon::class], #[neon::main]) is the developer-facing interface; understanding syn/quote macro expansion explains why macros generate boilerplate and validate at compile-time
  • Handle-based Memory Management — Neon uses scope-based handles (JsValue lifetimes tied to context) to prevent use-after-free and GC issues; this is core to why Neon is 'safe' compared to raw N-API
  • EventQueue / Thread-safe Channels — For async/background work, Neon's EventQueue (channel.rs) safely bridges Rust threads to the JavaScript event loop without blocking; essential for long-running operations
  • Type Coercion and Context — Neon's context object (FunctionContext, ModuleContext) is the only way to create/read JS values; understanding context-bound lifetimes prevents use-after-scope errors
  • LTO (Link-Time Optimization) — Neon enables LTO in release builds (Cargo.toml); critical for eliminating wrapper overhead and achieving near-C performance for hot Rust code
  • MSRV (Minimum Supported Rust Version) — Neon targets Rust 1.65+ (Cargo.toml); understanding MSRV prevents accidentally using newer syntax that breaks compatibility and affects dependency selection
  • nodejs/node-api-headers — Official Node-API (N-API) header definitions that Neon wraps; needed to understand the C layer Neon abstracts
  • neon-bindings/examples — Companion repo with runnable example Neon projects (crypto, image processing, ML) demonstrating real-world patterns
  • rustwasm/wasm-bindgen — Sibling Rust-to-JavaScript binding framework for WebAssembly; similar macro-driven API design philosophy but targets browser/WASM instead of Node
  • pyo3/pyo3 — Analogous Rust-to-Python binding framework; useful reference for understanding how procedural macros abstract FFI boilerplate
  • napi-rs/napi-rs — Alternative TypeScript-first N-API binding layer; competing approach to same problem with different design trade-offs

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for neon-macros export macros

The crates/neon-macros/src/export directory contains three macro types (class, function, global) with corresponding meta.rs files, but there's no visible test directory structure in the file listing. These macros are critical for the developer experience and should have dedicated integration tests validating code generation for different configurations (e.g., optional parameters, return types, error handling).

  • [ ] Create test directory structure: crates/neon-macros/tests/
  • [ ] Add test_export_function.rs validating #[export] function macro code generation with various signatures
  • [ ] Add test_export_class.rs validating #[export] class macro for methods, constructors, and property accessors
  • [ ] Add test_export_global.rs validating #[export] global macro for module-level exports
  • [ ] Verify macro expansion produces correct neon bindings using trybuild or similar

Add executor feature detection and tests for tokio integration

The crates/neon/src/executor/tokio.rs file exists but there's no visible corresponding test coverage. Given that async Rust/Node integration is complex, adding tests for the tokio executor would validate that futures are properly bridged between Rust and Node event loops, preventing subtle threading bugs.

  • [ ] Create crates/neon/tests/executor/ directory
  • [ ] Add test_tokio_executor_basic.rs for spawning and awaiting simple async tasks
  • [ ] Add test_tokio_executor_channel_integration.rs validating interaction between channel.rs event system and tokio executor
  • [ ] Add test_executor_feature_gates.rs to verify executor selection based on Cargo features
  • [ ] Document executor selection strategy in crates/neon/src/executor/mod.rs

Create missing benchmarks for object and class operations in bench/src/lib.rs

The bench/ directory exists with infrastructure (package.json, index.js) but bench/src/lib.rs is likely minimal. Object and class operations are performance-critical in Node native modules. Adding benchmarks for object property access, class instantiation, and method calls would establish performance baselines and prevent regressions.

  • [ ] Expand bench/src/lib.rs with benchmarks for object property get/set operations
  • [ ] Add benchmarks for class instantiation and method invocation across different class configurations
  • [ ] Add benchmarks for handle lifetime management and garbage collection interactions
  • [ ] Update bench/README.md with instructions for running specific benchmarks
  • [ ] Integrate benchmarks into .github/workflows/bench.yml with result comparison against baseline

🌿Good first issues

  • Add type conversion tests for JsBuffer and JsArrayBuffer in test/ to match the documentation claims about safe zero-copy bindings
  • Document the EventQueue::send_and_settle pattern in crates/neon/src/event/channel.rs with a worked example for background tasks
  • Create a diagnostic tool in crates/neon-macros that validates that #[neon::export] functions follow safe patterns (e.g., require FunctionContext first parameter)

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 252a5b6 — Merge pull request #1126 from neon-bindings/kv/array-extract (kjvalencik)
  • 2d071bc — feat(neon): Add Array extractor (kjvalencik)
  • 303eb3c — Merge pull request #1130 from neon-bindings/kv/json-option (kjvalencik)
  • c53500b — fix(neon): Allow extracting Json<Option<T>> when value is undefined (kjvalencik)
  • 22098e4 — fix(neon): class methods have proper .name property (#1127) (dherman)
  • b231761 — RC: v1.2.0-alpha.0 (dherman)
  • 7805af9 — Use absolute URL for Neon image in README (dherman)
  • 7eab710 — Merge pull request #1116 from neon-bindings/remove-linkme-workaround (kjvalencik)
  • c68b172 — Remove nightly workaround for linkme in CI workflow (kjvalencik)
  • cd7cdd2 — internal(neon): ensure test workers terminate (#1125) (dherman)

🔒Security observations

The Neon project demonstrates strong security practices for a Rust/Node.js binding library. No hardcoded secrets, credentials, or obvious injection vulnerabilities were detected in the provided file structure. The codebase uses Rust's memory safety features and maintains organized architecture with separate crate modules. Key areas for ongoing attention: (1) Regular dependency vulnerability scanning via 'cargo audit', (2) Careful review of unsafe FFI code at Rust-JavaScript boundaries, (3) Validation of data crossing the native module boundary. The presence of CI/CD workflows and code quality checks in GitHub Actions is a positive security indicator. Recommend implementing SBOM (Software Bill of Materials) generation and automated vulnerability scanning in the build pipeline.

  • Medium · Incomplete Dependency Audit Information — Cargo.toml, Cargo.lock. The Cargo.toml file was not fully provided for analysis. A comprehensive security audit requires examination of all dependencies and their versions to identify known vulnerabilities. The workspace configuration shows multiple crates but dependency versions are not visible. Fix: Regularly run 'cargo audit' to check for known vulnerabilities in dependencies. Implement automated dependency checking in CI/CD pipeline (as suggested by the presence of .github/workflows/ci.yml).
  • Low · Native Module Risk Exposure — crates/neon/src/sys/bindings/. As a Rust bindings library for Node.js native addons, this project interfaces with native code through FFI (Foreign Function Interface). While Rust provides memory safety guarantees, the interaction with Node.js C++ APIs and native modules creates potential attack surface for unsafe operations. Fix: Ensure all unsafe blocks are thoroughly documented and reviewed. Conduct regular security audits of FFI boundary code. Validate all data crossing the Rust-JavaScript boundary.
  • Low · Release Profile Configuration — Cargo.toml (profile.release section). The Cargo.toml enables LTO (Link Time Optimization) in release builds, which is good for performance and security, but may complicate debugging and increase build times. Fix: This is a best practice. Continue enabling LTO in release builds. Consider documenting the security implications in contribution guidelines.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · neon-bindings/neon — RepoPilot