Node ffi rust
Skill ComeOnOliver/skillshub/skills/Harmeet10000/skills/node-ffi-rust
Build high-performance native modules for Node.js using Rust and N-API via napi-rs. Use when optimizing compute-intensive operations, integrating system libraries, or requiring native performance without blocking the event loop.From its SKILL.md
npx -y skills add ComeOnOliver/skillshub --skill node-ffi-rustAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
4.5 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it
Node.js FFI Rust Skill
Build native extensions for Node.js using Rust with N-API bindings via napi-rs.
When to Use
- CPU-intensive operations: Crypto, compression, math, image processing
- System integration: OS-level operations, hardware access
- Large data processing: Batch operations on buffers/arrays
- Legacy libraries: Wrap existing Rust/C libraries
- Event loop safety: Offload blocking work without freezing the server
Quick Start
1. Create Project
cargo new --lib my-native-module
cd my-native-module
2. Add napi-rs
[package]
name = "my_native_module"
version = "0.1.0"
edition = "2021"
[dependencies]
napi = { version = "2", features = ["napi8"] }
napi-derive = "2"
[lib]
crate-type = ["cdylib"]
3. Write Rust Function
use napi_derive::napi;
#[napi]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
#[napi]
pub fn process_buffer(data: Vec<u8>) -> Vec<u8> {
data.iter().map(|b| b.wrapping_add(1)).collect()
}
4. Build
npm install -g @napi-rs/cli
napi build --release
5. Use in Node.js
const { add, processBuffer } = require('./index.node');
console.log(add(2, 3)); // 5
console.log(processBuffer([1,2,3])); // [2,3,4]
Architecture
JS → V8 → N-API → Rust → N-API → V8 → JS
Rust runs at native speed. N-API handles type conversion and memory safety.
Performance Considerations
Boundary Overhead
- Cost: 100-300 nanoseconds per call
- Dominates: Tiny functions called repeatedly
- Solution: Batch operations
Serialization Cost
- JSON: Very expensive (parse/stringify)
- TypedArray: Zero-copy (direct memory mapping)
- Buffers: Efficient (single allocation)
Rule of Thumb
If work per call > boundary cost → native wins
Critical Edge Cases
See references/EDGE_CASES.md for:
- Panic safety (catch_unwind required)
- Event loop blocking (use napi::Task)
- Buffer ownership (references vs copies)
- Async callbacks (thread safety)
- Cross-platform builds (prebuilt binaries)
- Struct layout (repr(C) for ABI stability)
Best Practices
- Use napi-rs — Safer than raw N-API, better DX
- Design around buffers — TypedArray/Buffer, not JS objects
- Batch operations — Process entire datasets, not row-by-row
- Avoid event loop blocking — Use
napi::Taskfor CPU work - Wrap panics —
std::panic::catch_unwind()always - Reuse buffers — Minimize allocations
- Version APIs — Struct layouts are ABI contracts
Optimization Checklist
- Minimize JS ↔ Rust calls
- Avoid JSON serialization
- Use TypedArray/Buffer
- Batch operations
- No event loop blocking
- Panics wrapped safely
- Boundary overhead benchmarked
- Prebuilt binaries available
- No JS references held across threads
- Buffers reused where possible
Example: Batch Array Processing
Rust (src/lib.rs):
use napi_derive::napi;
#[napi]
pub fn sum_array(data: Vec<u32>) -> u32 {
data.iter().sum()
}
#[napi]
pub fn process_batch(data: Vec<u8>, key: u8) -> Vec<u8> {
data.iter().map(|b| b ^ key).collect()
}
Node.js (index.js):
const { sumArray, processBatch } = require('./index.node');
const data = new Uint32Array([1, 2, 3, 4, 5]);
console.log(sumArray(Array.from(data))); // 15
const buffer = Buffer.from([72, 101, 108, 108, 111]);
console.log(processBatch(buffer, 42)); // XOR encrypted
This avoids 5 separate JS→Rust calls and processes data once.
Mental Model
Think of FFI as a toll booth between two countries.
- Many tiny cars (frequent small calls) → toll booth dominates
- One giant truck (batch operation) → efficient trip
This predicts nearly every FFI performance problem.
See Also
What ships with it
26.1 KB alongside SKILL.md, 3 of them executable
GitHub clipped this repository’s file list, so this is at least 6 files and may be more.
references/
- COMPLETE_SDK_REFERENCE.md5.5 KB
- EDGE_CASES.md8.3 KB
scripts/
- benchmark.shruns4.3 KB
- setup-async-example.shruns2.6 KB
- setup-project.shruns2.5 KB
- README.md2.9 KB