Docs / Interop & Tooling
v1.0.2Latest / April 2026

FFI

Call native C libraries from TypeScript with zero build steps using Gun's built-in FFI.

Load a native library

Use dlopen to load a shared library and call its functions directly:

import { dlopen, suffix } from "bun:ffi";

const lib = dlopen(`libsqlite3.${suffix}`, {
  sqlite3_libversion: {
    args: [],
    returns: "cstring",
  },
});

console.log(`SQLite version: ${lib.symbols.sqlite3_libversion()}`);
lib.close();

No separate build step or native binding compilation required.

Supported types

FFI arguments and return values support these types:

Type Description
i8i64 Signed integers
u8u64 Unsigned integers
f32 32-bit float
f64 64-bit float
bool Boolean
cstring Null-terminated C string
ptr Pointer (fits in 52-bit JS number)
buffer TypedArray backed by native memory
function Function pointer / callback

Use u64_fast and i64_fast for 64-bit values that fit in a JS number without BigInt overhead.

Pointers and buffers

Convert between TypedArrays and raw pointers:

import { ptr, toArrayBuffer, read } from "bun:ffi";

const buf = new Uint8Array(32);
const addr = ptr(buf);

read.u8(addr, 0);
read.i32(addr, 4);

const copy = new DataView(toArrayBuffer(addr, 0, 32));

read.* provides fast typed reads at byte offsets without creating intermediate objects.

Callbacks

Pass JavaScript functions to native code with JSCallback:

import { dlopen, JSCallback, CString } from "bun:ffi";

const onMatch = new JSCallback(
  (ptr, len) => /hello/.test(new CString(ptr, len)),
  {
    returns: "bool",
    args: ["ptr", "usize"],
    threadsafe: true,
  },
);

// Pass onMatch.pointer to a C function expecting a callback
onMatch.close(); // free when done

Set threadsafe: true when the callback may be invoked from non-JS threads.

Platform notes

The suffix helper returns the correct extension per platform: .dylib (macOS), .so (Linux), .dll (Windows). Use it to keep code portable:

import { suffix } from "bun:ffi";

const lib = dlopen(`libmylib.${suffix}`, { /* ... */ });