v1.0.2Latest / April 2026
C Compiler
Compile and call C code inline from TypeScript. No separate build step.
Compile C from TypeScript
Use cc from bun:ffi to compile C source and call it immediately:
import { cc } from "bun:ffi";
const { symbols } = cc({
source: "./math.c",
symbols: {
add: { args: ["int", "int"], returns: "int" },
},
});
console.log(symbols.add(3, 4)); // 7
// math.c
int add(int a, int b) {
return a + b;
}
No Makefile, no cargo, no node-gyp. The C code is compiled on first use and linked into the running process.
Define symbols
The symbols object maps C function names to their FFI signatures:
const { symbols } = cc({
source: "./image.c",
symbols: {
grayscale: {
args: ["ptr", "int", "int"],
returns: "int",
},
resize: {
args: ["ptr", "int", "int", "ptr", "int", "int"],
returns: "int",
},
},
});
Each entry specifies argument types and the return type using the same FFI type system (int, ptr, cstring, etc.).
Link system libraries
Pass library to link against installed shared libraries:
const { symbols } = cc({
source: "./sqlite_query.c",
symbols: {
query_version: { args: [], returns: "cstring" },
},
library: ["sqlite3"],
define: { NDEBUG: "1" },
});
library— link flags (e.g.["sqlite3"]links-lsqlite3)define— preprocessor defines passed to the compilerflags— additional compiler flags (include paths, warnings)
N-API interop
For functions that need to return JavaScript values (strings, objects, arrays), use N-API:
const { symbols } = cc({
source: "./greeting.c",
symbols: {
greet: { args: ["napi_env"], returns: "napi_value" },
},
});
console.log(symbols.greet()); // "Hello from C!"
#include <node/node_api.h>
napi_value greet(napi_env env) {
napi_value result;
napi_create_string_utf8(env, "Hello from C!", NAPI_AUTO_LENGTH, &result);
return result;
}
N-API allows full interop with JavaScript object types without manual serialization.