Skip to content
Back to skills

Bun Ffi Native Binding

ASecurity

Build high-performance native modules for JavaScript using Bun's FFI (Foreign Function Interface) with Zig or C. Use when optimizing hot paths, integrating system libraries, or requiring native performance for compute-intensive operations.

  • 43 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 30, 2026
developmentjavascriptjavabashfastapiapiperformancedocumentation

Works with

  • api

Security analysis

A100/100

Pro scans all 7 files and shows the line behind each finding

Scanned May 30, 2026

npx -y skills add ComeOnOliver/skillshub --skill bun-ffi-native-binding --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Bun Ffi Native Binding?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Bun Ffi Native Binding
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/comeonoliver-bun-ffi-native-binding/badge)](https://www.skillsdirectory.com/skills/comeonoliver-bun-ffi-native-binding)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: bun-ffi-native-binding
description: Build high-performance native modules for JavaScript using Bun's FFI (Foreign Function Interface) with Zig or C. Use when optimizing hot paths, integrating system libraries, or requiring native performance for compute-intensive operations.
license: MIT
compatibility: Requires Bun 1.0+, Zig compiler (for Zig bindings), or C compiler (for C FFI)
metadata:
  author: langchain-fastapi-production
  version: "1.0"
---

# Bun FFI Native Binding Skill

Build native extensions for JavaScript using Bun's tight integration with Zig and C via FFI.

## When to Use

- **Hot paths**: Compute-intensive operations (crypto, compression, math)
- **System integration**: Direct OS/hardware access
- **Large data processing**: Batch operations on arrays/buffers
- **Legacy libraries**: Wrap existing C/Zig libraries

## Two Approaches

### 1. Zig Bindgen (Recommended)

Zig functions compiled directly into Bun with zero-overhead bindings.

**Setup:**
```bash
bun add -d @zig/build
```

**Zig function** (`src/math.zig`):
```zig
const std = @import("std");
const jsc = @import("jsc");

pub fn add(global: *jsc.JSGlobalObject, a: i32, b: i32) !i32 {
    return std.math.add(i32, a, b) catch {
        return global.throwPretty("Integer overflow", .{});
    };
}
```

**Binding declaration** (`src/bindings.ts`):
```ts
import { t, fn } from "bindgen";

export const add = fn({
  args: { global: t.globalObject, a: t.i32, b: t.i32 },
  ret: t.i32
});
```

**Usage** (`index.ts`):
```ts
import { add } from "bun:math";
console.log(add(2, 3)); // 5
```

### 2. C FFI (Dynamic Loading)

Load C libraries at runtime without compilation.

**C function** (`lib.c`):
```c
int add(int a, int b) {
    return a + b;
}
```

**Compile:**
```bash
gcc -shared -fPIC -o lib.so lib.c
```

**Load in Bun** (`index.ts`):
```ts
import { dlopen, FFIType } from "bun:ffi";

const lib = dlopen("./lib.so", {
  add: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 }
});

console.log(lib.symbols.add(2, 3)); // 5
```

## Performance Considerations

### Bridge Cost
- **Overhead**: 10-100 nanoseconds per call
- **Dominates**: Tiny functions called repeatedly
- **Solution**: Batch operations

### Data Conversion
- **Overhead**: Proportional to payload size
- **Dominates**: Complex object marshaling
- **Solution**: Use typed arrays, avoid JSON

### Rule of Thumb
**If work per call > bridge cost → native wins**

## Critical Edge Cases

See [references/EDGE_CASES.md](references/EDGE_CASES.md) for:
- Exception boundaries (panics crash runtime)
- Memory ownership (who frees allocations?)
- Struct alignment (layout assumptions)
- GC interaction (pinning references)
- Thread safety (event loop constraints)
- ABI compatibility (C calling convention)

## Best Practices

1. **Minimize boundary crossings** — batch processing in native code
2. **Use typed arrays** — zero-copy buffer mapping
3. **Avoid per-call allocation** — reuse buffers
4. **Binary formats** — faster than JSON serialization
5. **Stable APIs** — version struct layouts
6. **Error handling** — convert panics to JS exceptions

## Optimization Checklist

- [ ] Minimize JS → native calls
- [ ] Avoid JSON across boundary
- [ ] Use typed arrays/buffers
- [ ] Batch processing in native
- [ ] Convert errors to JS exceptions
- [ ] No Zig panics escape to JS
- [ ] No global mutable state
- [ ] Benchmark boundary latency
- [ ] No per-call memory allocation
- [ ] Thread safety verified

## Example: Batch Array Processing

**Zig** (`src/process.zig`):
```zig
pub fn processArray(global: *jsc.JSGlobalObject, ptr: [*]u32, len: usize) !u32 {
    var sum: u32 = 0;
    for (0..len) |i| {
        sum +|= ptr[i];
    }
    return sum;
}
```

**JS** (`index.ts`):
```ts
const data = new Uint32Array([1, 2, 3, 4, 5]);
const sum = processArray(data.buffer, data.length);
```

This avoids 5 separate JS→native calls and marshals data once.

## See Also

- [Complete SDK Reference](references/COMPLETE_SDK_REFERENCE.md)
- [Zig Documentation](https://ziglang.org/documentation/)
- [Bun FFI Docs](https://bun.sh/docs/ffi)

Files in this skill

  • README.md2.6 KB
  • SKILL.md4 KB
  • references/COMPLETE_SDK_REFERENCE.md4.3 KB
  • references/EDGE_CASES.md4.9 KB
  • scripts/benchmark.sh3.2 KB
  • scripts/setup-c-ffi.sh2.9 KB
  • scripts/setup-project.sh2.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…