bun:ffi module lets you call native shared libraries directly from JavaScript. It supports any language that exposes a C ABI, including C, C++, Rust, Zig, C#, Nim, and Kotlin.
How it works
When you calldlopen, Bun generates and JIT-compiles C bindings that efficiently convert values between JavaScript types and native types. To compile these bindings, Bun embeds TinyCC, a small and fast C compiler. This approach makes bun:ffi roughly 2–6x faster than Node.js FFI via Node-API.
Basic usage
Usedlopen to load a shared library and declare the symbols you want to call.
Calling SQLite
A complete example: print the SQLite version number.Compiling native libraries
- Zig
- Rust
- C++
add.zig
FFI types
UseFFIType to declare the native type for each argument and return value.
Strings
JavaScript strings are UTF-16. C strings are null-terminated UTF-8. Bun providesCString to bridge the two.
CString extends JavaScript’s built-in String and automatically reads until the null terminator, transcoding from UTF-8 to UTF-16 as needed.
CString clones the string content, so it’s safe to use after the original pointer has been freed.
FFIType.cstring is used as a return type, Bun automatically coerces the pointer to a JavaScript string. When used as an argument type, it behaves like ptr.
Pointers
Bun represents native pointers as JavaScriptnumber values.
64-bit processors support up to 52 bits of addressable space. JavaScript numbers support 53 bits of usable space, so all valid pointer addresses fit in a JavaScript
number without precision loss.Getting a pointer to a TypedArray
Converting a pointer to an ArrayBuffer
Reading from a pointer
For long-lived pointers, useDataView:
read helper — it’s faster because it skips ArrayBuffer allocation:
read functions by type:
Passing a pointer as an argument
Where a native function expects a pointer, pass aTypedArray directly. Bun converts it automatically.
Memory management
bun:ffi does not manage memory. You are responsible for freeing any memory allocated by native code.
To track when a TypedArray is garbage collected from JavaScript, use a FinalizationRegistry.
To receive a callback when a TypedArray is freed from native code, pass a deallocator pointer to toArrayBuffer:
JSTypedArrayBytesDeallocator:
Callbacks
UseJSCallback to pass a JavaScript function to native code. The native library can then call back into JavaScript.
Async functions are not yet supported as
JSCallback targets.close() on a JSCallback when you’re done with it to free memory.
Thread-safe callbacks
JSCallback has experimental support for thread-safe callbacks. Enable it with the threadsafe option:
Thread-safe callbacks currently work best when called from a thread that is already running JavaScript, such as a
Worker. Future versions of Bun will support calling them from any thread, including threads spawned by native libraries.Function pointers
UseCFunction to call a function pointer you already have a reference to — for example, one obtained from a Node-API module.
linkSymbols:
Platform suffixes
Thesuffix export resolves to the correct shared library extension for the current platform.