UnFFI
Runtimes

Bun

Using unffi on Bun — bun:ffi, fast 64-bit ints, NAPI interop, zero-copy.

unffi on Bun uses bun:ffi directly. Symbols are JIT-compiled to native trampolines — no JS wrapper overhead per call.

Quick start

import { ,  } from 'unffi'

const  = await ('./libmath.dylib', {
  :  { : [., .], : . },
  : { : [.],        : . },
})

const sum  = ..(3, 4)
const sum: number
const root = ..(2.0)
const root: number

Fast 64-bit integers

t.i64 and t.u64 always return bigint. If you know the value fits in a JS number (≤ 2^53), use the fast variant to skip BigInt allocation:

import { ,  } from 'unffi'

const  = await ('./counter.dylib', {
  : { : [], : . },
})

const precise = ..()
const precise: bigint

On Bun, you can also use t.bun.i64_fast instead of t.i64 — it returns number | bigint, skipping BigInt allocation when the value fits in a double.

t.i64 always gives bigint. t.bun.i64_fast gives number | bigint — skips BigInt allocation when the value fits.

i64_fast silently loses precision above 2^53. Only use it when values are bounded.

Zero-copy buffers

Use t.buffer for TypedArray arguments — unffi passes the backing pointer directly:

import { ,  } from 'unffi'

const  = await ('./fill.dylib', {
  : { : [., .], : . },
})

const  = new (1024)
const result = ..(, .)
const result: void
// buf is populated in-place

Callbacks

Pass a JS function directly where t.fn is in the schema:

import { ,  } from 'unffi'

const  = await ('./sorter.dylib', {
  : {
    : [., ., .([., .], .)],
    : .,
  },
})

..(new (10), 10, (a, ) => {
a: number
return - })

The callback's a and b are typed as number from t.i32.

Async / nonblocking calls

Mark slow symbols async: true to run them on a thread pool:

import { ,  } from 'unffi'

const  = await ('./codec.dylib', {
  : { : [., .], : ., : true },
})

const outLen = await ..(new (1024), 1024)
const outLen: number

NAPI interop

For native addons that expose a Node-API interface, use t.bun.napi_env and t.bun.napi_value:

await using addon = await dlopen('./addon.node', {
  napi_register_module_v1: {
    args: [t.bun.napi_env, t.bun.napi_value],
    returns: t.bun.napi_value,
  },
})

On this page