> bun-ffi-native-binding

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.

fetch
$curl "https://skillshub.wtf/Harmeet10000/skills/bun-ffi-native-binding?format=md"
SKILL.mdbun-ffi-native-binding

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:

bun add -d @zig/build

Zig function (src/math.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):

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):

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):

int add(int a, int b) {
    return a + b;
}

Compile:

gcc -shared -fPIC -o lib.so lib.c

Load in Bun (index.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 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):

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):

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

> related_skills --same-repo

> vibe-ppt

Convert this into a web based slide deck using reveal.js. Use the following brand colour and logo. Primary colour: #EE4822 Theme: Light Logo: https://media.licdn.com/dms/image/v2/D560BAQFeaNrDEATcKQ/company-logo_200_200/company-logo_200_200/0/1709465010800/100xengineers_logo?e=2147483647&v=beta&t=qKncqAfB_j9ckDOxOx1eN9EEPocLTbNqliLnAU3sP6c Slide Content: Vibe Coding with Gemini Canvas Slide 1: Vibe Coding with Gemini Canvas Slide 2: What is Vibe Coding? Vibe Coding: Use natural language pro

> upwork-scrape-apply

# Upwork Job Scrape & Apply Pipeline Scrape Upwork jobs matching AI/automation keywords, generate personalized cover letters and proposals, and output to a Google Sheet with one-click apply links. ## Inputs - **Keywords**: List of search terms (default: automation, ai agent, n8n, gpt, workflow, api integration, scraping, ai consultant) - **Limit**: Max jobs to fetch (default: 50) - **Days**: Only jobs from last N days (default: 1 = last 24 hours) - **Filters**: - `--verified-payment`: Only

> ui-ux-pro-max

UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 9 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: g

> typescript-magician

Designs complex generic types, refactors `any` types to strict alternatives, creates type guards and utility types, and resolves TypeScript compiler errors. Use when the user asks about TypeScript (TS) types, generics, type inference, type guards, removing `any` types, strict typing, type errors, `infer`, `extends`, conditional types, mapped types, template literal types, branded/opaque types, or utility types like `Partial`, `Record`, `ReturnType`, and `Awaited`.

┌ stats

installs/wk0
░░░░░░░░░░
github stars6
░░░░░░░░░
first seenApr 3, 2026
└────────────