Bindgen scans .bind.ts files for function and class definitions
The bindings generator scans for *.bind.ts files to find function and class definitions, and generates glue code to interop between JavaScript and native code. This system is replacing the Classes generator, JS2Native, and other code generation systems.
Rust function implementation for bindgen
A Rust function for bindgen takes a JSGlobalObject reference as the first parameter and returns JsResult<T>. Errors must be converted to thrown exceptions using global.throw(). The function should be placed in a file like src/jsc/bindgen_test.rs, with a corresponding .bind.ts file next to it.
Bindgen .bind.ts file format for functions
A .bind.ts file defines the API schema using fn() from bindgen. The fn() function takes an object with 'args' and 'ret' properties. Args maps argument names to types using t.* type descriptors. Example: export const add = fn({ args: { global: t.globalObject, a: t.i32, b: t.i32.default(-1), }, ret: t.i32, });
Accessing bindgen-generated functions in Rust
To construct a JSFunction wrapping a native implementation, use generated::create_<function_name>_callback(global), where generated is imported as crate::r#gen::<basename>. For a bindgen_test.bind.ts file, this is crate::r#gen::bindgen_test.
Accessing bindgen functions from JavaScript
In JS files in src/js/, use $bindgenFn("<bindfile>.bind.ts", "<function_name>") to get a handle to the native implementation. This works through a hand-written js2native_bindgen_<basename>_<fn> export in src/runtime/hw_exports.rs.
Bindgen naming convention for Rust functions
Exported bindgen functions are converted from camelCase to snake_case on the Rust side. For example, requiredAndOptionalArg becomes required_and_optional_arg. The hand-written callback constructor follows the same convention: create_required_and_optional_arg_callback.
String types in bindgen: t.DOMString, t.ByteString, t.USVString
Bindgen provides three string types that map to WebIDL counterparts: t.DOMString (loosest, most recommended), t.ByteString (only valid latin1 characters), and t.USVString (no invalid surrogate pairs, correctly UTF-8 representable). All convert to bun_core::String in native code. t.UTF8String eagerly converts to UTF-8 and passes a &[u8] slice (WTF-8 data) to the native callback.
Function variants (overloads) in bindgen
Use the 'variants' key to declare multiple overloads of a function. Each variant has its own args and ret. Each variant gets a numbered Rust function (action1, action2, etc.) matching the order of declaration.
t.dictionary for JavaScript objects in bindgen
A dictionary describes a JavaScript object, typically a function input. For function outputs, use a class type instead so you can add methods and support destructuring.
t.stringEnum creates WebIDL enumeration
t.stringEnum creates a WebIDL enumeration and generates a new enum type. Bindgen sorts t.stringEnum values alphabetically before emitting the C++ enum class, so discriminants must match the generated header's alphabetical order, not the .bind.ts declaration order. WebIDL encourages kebab-case for enumeration values.
stringEnum example: Formatter enum
Example from fmt_jsc.bind.ts: export const Formatter = t.stringEnum("highlight-javascript", "highlight-javascript-redacted", "escape-powershell"); The Rust enum becomes #[repr(u8)] with variants sorted alphabetically: EscapePowershell = 0, HighlightJavascript = 1, HighlightJavascriptRedacted = 2.
t.oneOf for union types in bindgen
A oneOf is a union of two or more types, represented as a Rust enum with one variant per member type.
Bindgen type attributes: .required, .optional, .default(T)
Three attributes can be chained onto t.* types: .required (in dictionary parameters only), .optional (in function arguments only, lowers to Rust Option<T>), and .default(T). Only one of these attributes can be applied, and it must be applied last.
Optional and required argument example in bindgen
Example: export const requiredAndOptionalArg = fn({ args: { a: t.boolean, b: t.usize.optional, c: t.i32.enforceRange(0, 100).default(42), d: t.u8.optional, }, ret: t.i32, }); Becomes: pub fn required_and_optional_arg(a: bool, b: Option<usize>, c: i32, d: Option<u8>) -> i32
Integer attributes in bindgen: clamp and enforceRange
Integer types take clamp or enforceRange to customize overflow behavior. clamp wraps values to the type's range or a specified range. enforceRange enforces values stay in range and can accept a range like enforceRange(0, 1000). Both can be combined with .default() or .optional.
Node.js validator functions in bindgen: validateNumber, validateInt32, validateInteger
Node.js validator functions are available for integer and number types. validateNumber checks typeof value === 'number', validateInt32 validates i32 range, validateInteger validates f64 within safe integer range. These are stricter than WebIDL's enforceRange and produce error messages matching Node.js exactly.
Integer overflow handling in bindgen Rust functions
Binding functions can propagate out-of-memory and JS exceptions directly. Other failures like integer overflow must be converted into a thrown error using global.throw() with a descriptive message.
Bun includes runtime, package manager, test runner, and bundler
Bun ships as a single, dependency-free binary and includes four main components: a runtime for executing JavaScript/TypeScript, a package manager for fast installs with workspaces and overrides, a Jest-compatible test runner with TypeScript support, and a bundler for native bundling of JS/TS/JSX with splitting and plugins.
CPU profiling with --cpu-prof flag
Run 'bun --cpu-prof script.js' to generate a .cpuprofile file in Chrome DevTools format that can be opened in Chrome DevTools Performance tab or VS Code CPU profiler to identify performance bottlenecks.
CPU profiling markdown format with --cpu-prof-md
Run 'bun --cpu-prof-md script.js' to generate a markdown CPU profile that is grep-friendly and designed for LLM analysis. Can be combined with --cpu-prof to generate both formats.
CPU profiling options and flags
CPU profiling supports: --cpu-prof (generates .cpuprofile JSON file), --cpu-prof-md (generates markdown profile), --cpu-prof-name <filename> (set output filename), --cpu-prof-dir <dir> (set output directory). Can also use BUN_OPTIONS environment variable.
Heap profiling with --heap-prof flag
Run 'bun --heap-prof script.js' to write a full V8-format heap snapshot on exit using Node.js diagnostic filename format (Heap.<yyyymmdd>.<hhmmss>.<pid>.<tid>.<seq>.heapprofile). Load in Chrome DevTools Memory tab.
Heap profiling markdown format with --heap-prof-md
Run 'bun --heap-prof-md script.js' to generate a markdown heap profile for CLI analysis. If both --heap-prof and --heap-prof-md are specified, Bun uses the markdown format.
Heap profiling options and flags
Heap profiling supports: --heap-prof (writes .heapprofile file on exit), --heap-prof-md (generates markdown heap profile on exit), --heap-prof-name <filename> (set output filename), --heap-prof-dir <dir> (set output directory), --heap-prof-interval <bytes> (accepted for Node.js compatibility but does not affect behavior as JavaScriptCore has no allocation sampling).
Recommended benchmarking tools for different use cases
For microbenchmarks use mitata. For load testing use HTTP benchmarking tools at least as fast as Bun.serve(): bombardier, oha, or http_load_test (Node.js tools like autocannon are not fast enough). For benchmarking scripts or CLI commands use hyperfine.
Bun has two separate heaps
Bun maintains one heap for the JavaScript runtime and a separate heap for everything else (native memory), using mimalloc for the native heap.