bun:ffi

Bun

Module

bun:ffi

The 'bun:ffi' module enables high-performance calls to native libraries from JavaScript. It works with languages that support the C ABI (Zig, Rust, C/C++, C#, Nim, Kotlin, etc).

Bun generates and just-in-time compiles C bindings that efficiently convert values between JavaScript types and native types, using embedded TinyCC (a small and fast C compiler). According to benchmarks, bun:ffi is roughly 2-6x faster than Node.js FFI via Node-API.

⚠️ Warning — bun:ffi is experimental, with known bugs and limitations, and should not be relied on in production. The most stable way to interact with native code from Bun is to write a Node-API module.

functioncc<Fns extends Record<string, FFIFunction>>(options:
{

define: Record<string, string>

Map of symbols to define where the key is the symbol name and the value is the symbol value

Equivalent to -D option in gcc/clang.

flags: string | string[]

Flags to pass to the compiler. Note: we do not make gurantees about which specific version of the compiler is used.

include: string | string[]

Include directories to pass to the compiler

Equivalent to -I option in gcc/clang.

library: string | string[]

Library names to link against

Equivalent to -l option in gcc/clang.

source: string | URL | BunFile

File path to an ISO C11 source file to compile and link

symbols: Fns

Map of symbols to load where the key is the symbol name and the value is the FFIFunction

}
): Library<Fns>

Experimental: Compile ISO C11 source code using TinyCC, and make symbols available as functions to JavaScript.

returns

Library<Fns>

functionCFunction(fn: FFIFunction &
{

ptr: Pointer

}
): CallableFunction &
{

close(): void

Free the memory allocated by the wrapping function

}

Turn a native library's function pointer into a JavaScript function

Libraries using Node-API & bun:ffi in the same module could use this to skip an extra dlopen() step.

fn

FFIFunction declaration. ptr is required

classCStringextendsString

Get a string from a UTF-8 encoded C string If byteLength is not provided, the string is assumed to be null-terminated.

staticfromCharCode(codes: number[]): string

staticfromCodePoint(codePoints: number[]): string

Return the String value whose elements are, in order, the elements in the List elements. If length is 0, the empty string is returned.

staticraw(template:
{

raw: readonly string[] | ArrayLike<string>

}
, substitutions: any[]): string

String.raw is usually used as a tag function of a Tagged Template String. When called as such, the first argument will be a well formed template call site object and the rest parameter will contain the substitution values. It can also be called directly, for example, to interleave strings and values from your own tag function, and in this case the only thing it needs from the first argument is the raw property.

template

A well-formed template string call site representation.

substitutions

A set of substitution values.

constructor(ptr: Pointer, byteOffset?: number, byteLength?: number): CString

Get a string from a UTF-8 encoded C string If byteLength is not provided, the string is assumed to be null-terminated.

ptr

The pointer to the C string

byteOffset

bytes to skip before reading

byteLength

bytes to read

byteLength: number

byteOffset: number

length: number

Returns the length of a String object.

ptr: Pointer

The ptr to the C string

This CString instance is a clone of the string, so it is safe to continue using this instance after the ptr has been freed.

[Symbol.iterator](): StringIterator<string>

Iterator

at(index: number): undefined | string

Returns a new String consisting of the single UTF-16 code unit located at the specified index.

index

The zero-based index of the desired code unit. A negative index will count back from the last item.

charAt(pos: number): string

Returns the character at the specified index.

pos

The zero-based index of the desired character.

charCodeAt(index: number): number

Returns the Unicode value of the character at the specified location.

index

The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.

codePointAt(pos: number): undefined | number

Returns a nonnegative integer Number less than 1114112 (0x110000) that is the code point value of the UTF-16 encoded code point starting at the string element at position pos in the String resulting from converting this object to a String. If there is no element at that position, the result is undefined. If a valid UTF-16 surrogate pair does not begin at pos, the result is the code unit at pos.

concat(strings: string[]): string

Returns a string that contains the concatenation of two or more strings.

strings

The strings to append to the end of the string.

endsWith(searchString: string, endPosition?: number): boolean

Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at endPosition – length(this). Otherwise returns false.

includes(searchString: string, position?: number): boolean

Returns true if searchString appears as a substring of the result of converting this object to a String, at one or more positions that are greater than or equal to position; otherwise, returns false.

searchString

search string

position

If position is undefined, 0 is assumed, so as to search all of the String.

indexOf(searchString: string, position?: number): number

Returns the position of the first occurrence of a substring.

searchString

The substring to search for in the string

position

The index at which to begin searching the String object. If omitted, search starts at the beginning of the string.

isWellFormed(): boolean

Returns true if all leading surrogates and trailing surrogates appear paired and in order.

lastIndexOf(searchString: string, position?: number): number

Returns the last occurrence of a substring in the string.

searchString

The substring to search for.

position

The index at which to begin searching. If omitted, the search begins at the end of the string.

localeCompare(that: string): number

Determines whether two strings are equivalent in the current locale.

that

String to compare to target string

match(regexp: string | RegExp): null | RegExpMatchArray

Matches a string with a regular expression, and returns an array containing the results of that search.

regexp

A variable name or string literal containing the regular expression pattern and flags.

matchAll(regexp: RegExp): RegExpStringIterator<RegExpExecArray>

Matches a string with a regular expression, and returns an iterable of matches containing the results of that search.

regexp

A variable name or string literal containing the regular expression pattern and flags.

normalize(form: 'NFC' | 'NFD' | 'NFKC' | 'NFKD'): string

Returns the String value result of normalizing the string into the normalization form named by form as specified in Unicode Standard Annex #15, Unicode Normalization Forms.

form

Applicable values: "NFC", "NFD", "NFKC", or "NFKD", If not specified default is "NFC"

padEnd(maxLength: number, fillString?: string): string

Pads the current string with a given string (possibly repeated) so that the resulting string reaches a given length. The padding is applied from the end (right) of the current string.

maxLength

The length of the resulting string once the current string has been padded. If this parameter is smaller than the current string's length, the current string will be returned as it is.

fillString

The string to pad the current string with. If this string is too long, it will be truncated and the left-most part will be applied. The default value for this parameter is " " (U+0020).

padStart(maxLength: number, fillString?: string): string

Pads the current string with a given string (possibly repeated) so that the resulting string reaches a given length. The padding is applied from the start (left) of the current string.

maxLength

The length of the resulting string once the current string has been padded. If this parameter is smaller than the current string's length, the current string will be returned as it is.

fillString

The string to pad the current string with. If this string is too long, it will be truncated and the left-most part will be applied. The default value for this parameter is " " (U+0020).

repeat(count: number): string

Returns a String value that is made from count copies appended together. If count is 0, the empty string is returned.

count

number of copies to append

replace(searchValue: string | RegExp, replaceValue: string): string

Replaces text in a string, using a regular expression or search string.

searchValue

A string or regular expression to search for.

replaceValue

A string containing the text to replace. When the searchValue is a RegExp, all matches are replaced if the g flag is set (or only those matches at the beginning, if the y flag is also present). Otherwise, only the first match of searchValue is replaced.

replaceAll(searchValue: string | RegExp, replaceValue: string): string

Replace all instances of a substring in a string, using a regular expression or search string.

searchValue

A string to search for.

replaceValue

A string containing the text to replace for every successful match of searchValue in this string.

search(regexp: string | RegExp): number

Finds the first substring match in a regular expression search.

regexp

The regular expression pattern and applicable flags.

slice(start?: number, end?: number): string

Returns a section of a string.

start

The index to the beginning of the specified portion of stringObj.

end

The index to the end of the specified portion of stringObj. The substring includes the characters up to, but not including, the character indicated by end. If this value is not specified, the substring continues to the end of stringObj.

split(separator: string | RegExp, limit?: number): string[]

Split a string into substrings using the specified separator and return them as an array.

separator

A string that identifies character or characters to use in separating the string. If omitted, a single-element array containing the entire string is returned.

limit

A value used to limit the number of elements returned in the array.

startsWith(searchString: string, position?: number): boolean

Returns true if the sequence of elements of searchString converted to a String is the same as the corresponding elements of this object (converted to a String) starting at position. Otherwise returns false.

substring(start: number, end?: number): string

Returns the substring at the specified location within a String object.

start

The zero-based index number indicating the beginning of the substring.

end

Zero-based index number indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end. If end is omitted, the characters from start through the end of the original string are returned.

toLocaleLowerCase(locales?: string | string[]): string

Converts all alphabetic characters to lowercase, taking into account the host environment's current locale.

toLocaleUpperCase(locales?: string | string[]): string

Returns a string where all alphabetic characters have been converted to uppercase, taking into account the host environment's current locale.

toLowerCase(): string

Converts all the alphabetic characters in a string to lowercase.

toString(): string

Returns a string representation of a string.

toUpperCase(): string

Converts all the alphabetic characters in a string to uppercase.

toWellFormed(): string

Returns a string where all lone or out-of-order surrogates have been replaced by the Unicode replacement character (U+FFFD).

trim(): string

Removes the leading and trailing white space and line terminator characters from a string.

trimEnd(): string

Removes the trailing white space and line terminator characters from a string.

trimStart(): string

Removes the leading white space and line terminator characters from a string.

valueOf(): string

Returns the primitive value of the specified object.

functiondlopen<Fns extends Record<string, FFIFunction>>(name: string | URL | BunFile, symbols: Fns): Library<Fns>

Open a library using "bun:ffi"

name

The name of the library or file path. This will be passed to dlopen()

symbols

Map of symbols to load where the key is the symbol name and the value is the FFIFunction

EFFIType

bool
buffer
char
cstring
double
f32
f64
float
function
i16
i32
i64
i64_fast
i8
int
int16_t
int32_t
int64_t
int8_t
napi_env
napi_value
pointer
ptr
u16
u32
u64
u64_fast
u8
uint16_t
uint32_t
uint64_t
uint8_t
void

classJSCallback

Pass a JavaScript function to FFI (Foreign Function Interface)

constructor(callback: (args: any[]) => any, definition: FFIFunction): JSCallback

Enable a JavaScript callback function to be passed to C with bun:ffi

callback

The JavaScript function to be called

definition

The C function definition

ptr: null | Pointer

The pointer to the C function

Becomes null once JSCallback.prototype.close is called

threadsafe: boolean

Can the callback be called from a different thread?

close(): void

Free the memory allocated for the callback

If called multiple times, does nothing after the first call.

functionlinkSymbols<Fns extends Record<string, FFIFunction>>(symbols: Fns): Library<Fns>

Link a map of symbols to JavaScript functions

This lets you use native libraries that were already loaded somehow. You usually will want dlopen instead.

You could use this with Node-API to skip loading a second time.

symbols

Map of symbols to load where the key is the symbol name and the value is the FFIFunction

functionptr(view: ArrayBufferLike | TypedArray<ArrayBufferLike> | DataView<ArrayBufferLike>, byteOffset?: number): Pointer

Get the pointer backing a TypedArray or ArrayBuffer

Use this to pass TypedArray or ArrayBuffer to C functions.

This is for use with FFI functions. For performance reasons, FFI will not automatically convert typed arrays to C pointers.

view

the typed array or array buffer to get the pointer for

byteOffset

optional offset into the view in bytes

namespaceread

functionf32(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functionf64(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functioni16(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functioni32(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functioni64(ptr: Pointer, byteOffset?: number): bigint

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functioni8(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functionintptr(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functionptr(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functionu16(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functionu32(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functionu64(ptr: Pointer, byteOffset?: number): bigint

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functionu8(ptr: Pointer, byteOffset?: number): number

The read function behaves similarly to DataView, but it's usually faster because it doesn't need to create a DataView or ArrayBuffer.

ptr

The memory address to read

byteOffset

bytes to skip before reading

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

Vsuffix: string

Platform-specific file extension name for dynamic libraries

"." is not included

functiontoArrayBuffer(ptr: Pointer, byteOffset?: number, byteLength?: number): ArrayBuffer

Read a pointer as an ArrayBuffer

If byteLength is not provided, the pointer is assumed to be 0-terminated.

ptr

The memory address to read

byteOffset

bytes to skip before reading

byteLength

bytes to read

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functiontoBuffer(ptr: Pointer, byteOffset?: number, byteLength?: number): Buffer

Read a pointer as a Buffer

If byteLength is not provided, the pointer is assumed to be 0-terminated.

ptr

The memory address to read

byteOffset

bytes to skip before reading

byteLength

bytes to read

While there are some checks to catch invalid pointers, this is a difficult thing to do safely. Passing an invalid pointer can crash the program and reading beyond the bounds of the pointer will crash the program or cause undefined behavior. Use with care!

functionviewSource(symbols: Readonly, is_callback?: false): string[]

View the generated C code for FFI bindings

You probably won't need this unless there's a bug in the FFI bindings generator or you're just curious.

Type Definitions

typeConvertFns<Fns extends Symbols>
={ [K in keyof Fns]:
{

__ffi_function_callable: typeof FFIFunctionCallableSymbol

}
}

interfaceFFIFunction

args: readonly FFITypeOrString[]

Arguments to a FFI function (C ABI)

Defaults to an empty array, which means no arguments.

To pass a pointer, use "ptr" or "pointer" as the type name. To get a pointer, see ptr.

ptr: bigint | Pointer

Function pointer to the native function

If provided, instead of using dlsym() to lookup the function, Bun will use this instead. This pointer should not be null (0).

This is useful if the library has already been loaded or if the module is also using Node-API.

returns: FFITypeOrString

Return type to a FFI function (C ABI)

Defaults to FFIType.void

To pass a pointer, use "ptr" or "pointer" as the type name. To get a pointer, see ptr.

threadsafe: boolean

Can C/FFI code call this function from a separate thread?

Only supported with JSCallback.

This does not make the function run in a separate thread. It is still up to the application/library to run their code in a separate thread.

By default, JSCallback calls are not thread-safe. Turning this on incurs a small performance penalty for every function call. That small performance penalty needs to be less than the performance gain from running the function in a separate thread.

interfaceFFITypeToArgsType

0: number

1: number

10: number

11: boolean

12: null | TypedArray<ArrayBufferLike> | Pointer | CString

13: undefined

14: null | TypedArray<ArrayBufferLike> | Pointer | CString

15: number | bigint

16: number | bigint

18: unknown

19: unknown

2: number

20: TypedArray<ArrayBufferLike> | DataView<ArrayBufferLike>

3: number

4: number

5: number

6: number

7: number | bigint

8: number | bigint

9: number

interfaceFFITypeToReturnsType

0: number

1: number

10: number

11: boolean

12: null | Pointer

13: undefined

15: number | bigint

16: number | bigint

17: null | Pointer

18: unknown

19: unknown

2: number

20: TypedArray<ArrayBufferLike> | DataView<ArrayBufferLike>

3: number

4: number

5: number

6: number

7: bigint

8: bigint

9: number

interfaceLibrary<Fns extends Symbols>

close(): void

dlclose the library, unloading the symbols and freeing allocated memory.

Once called, the library is no longer usable.

Calling a function from a library that has been closed is undefined behavior.

typePointer
=number &
{

__pointer__: null

}

typeSymbols=Readonly<Record<string, FFIFunction>>

typeToFFIType<T extends FFITypeOrString>=T extends FFIType ? T : T extends string ? FFITypeStringToType[T] : never