
Node.js 26.9.0 shipped on September 16 with one change that got buried under the usual release noise: node:ffi is now on by default. No flags. No build step. No C++ addon. If you’re running Node 26.9 or later, you can load any native shared library from plain JavaScript right now.
Bun and Deno have had first-class FFI for years. Node has been the holdout — you either wrote a C++ N-API addon or pulled in community packages like ffi-napi that hadn’t seen a meaningful update in months. That gap just closed.
What Actually Changed
Up through Node.js 26.8.2, using node:ffi required --experimental-ffi. As of 26.9.0, the module is on by default. The old flag didn’t just get removed — it got inverted. Passing --experimental-ffi now disables the module. If you had that flag in your start scripts to enable FFI, drop it. If you want to keep FFI off, that’s now the flag to use.
The change traces to a single SEMVER-MINOR commit: “ffi: enable module by default” by Matteo Collina (PR #65475). One line in the changelog, significant behavioral shift.
One caveat: if you’re running Node’s Permission Model, you still need --allow-ffi. The module being on by default doesn’t bypass capability restrictions.
About That 37ns Benchmark
The most-shared number from this release is 37 nanoseconds per FFI call, compared to ~35ns for a compiled N-API addon. Sounds nearly equivalent. Here’s the context that matters: that figure came from a benchmark where V8 had already JIT-compiled the JS and N-API versions before the FFI run in the same process. Running FFI in isolation puts the number in the 40–45ns range.
So FFI is not quite as fast as a hand-rolled native addon. But that misses the actual value proposition. If you already have a tuned N-API binding, you don’t need FFI. FFI is for the case where you have a native library you didn’t write and aren’t going to wrap in C++. The comparison isn’t “FFI vs. my existing addon” — it’s “FFI vs. the hours it takes to write that addon.”
What node:ffi Is Actually For
The module’s sweet spot is integrating with native libraries you don’t own: system APIs, hardware SDKs, or any C library where an npm wrapper doesn’t exist. Five lines to call a native function:
import { dlopen, suffix } from 'node:ffi';
const { functions } = dlopen(`libsqlite3.${suffix}`, {
sqlite3_libversion: {
parameters: [],
result: 'pointer'
}
});
console.log(functions.sqlite3_libversion());
The suffix export handles platform differences automatically — .so on Linux, .dylib on macOS, .dll on Windows. Check the official node:ffi documentation for the full type system and pointer handling API.
Where FFI doesn’t belong: hot loops, complex nested structs, or any production path where you need the ABI stability guarantees that N-API provides across major Node versions. The docs are explicit: this API is unsafe. A wrong pointer type or freed-memory access crashes the process. Treat it accordingly.
The Rest of 26.9.0
FFI is the headline, but three other changes in this release are worth a look.
Web Workers in thread contexts. Workers running inside worker_threads now get first-class postMessage/onmessage support. This unlocks real CPU parallelism for compute-heavy workloads without the overhead of spawning a child process.
Experimental DTLS. Node gets TLS over UDP alongside its existing QUIC implementation. DTLS is the protocol under WebRTC, low-latency streaming, and a lot of IoT tooling. If you’ve been shelling out to native code for DTLS, there’s now a first-party path — experimental, but there.
Crypto upgrades. A generic MAC API consolidates HMAC, CMAC, and similar interfaces, and OpenSSL provider discovery means Node now queries loaded providers dynamically for available ciphers and hash algorithms instead of a compiled-in list. Relevant if you’re running custom OpenSSL provider setups.
When to Upgrade
Node.js 26 enters Long-Term Support on October 28, 2026. For production services, that’s your target date. Node 24 remains in maintenance until April 2028, so there’s no pressure — the clean upgrade window opens in five weeks.
If you want to test FFI now, 26.9.0 is stable enough for development and staging environments. The full 26.9.0 release notes cover all the SEMVER-MINOR and patch changes included in this build.
Node.js 26 is also the last release under the old two-release-per-year cadence. Starting with Node 27, the project moves to one major release per year aligned with the calendar, and every release becomes LTS. The odd/even numbering confusion ends here.













