Modern FFI (Foreign Function Interface) library for Node.js - a unified replacement for ffi-napi, ref-napi, ref-struct-napi, ref-array-napi, and bindings packages.
Built on koffi for better performance, safety, and cross-platform compatibility.
- Unified API - Single package replaces 5+ legacy packages
- Type-safe - Full TypeScript support with type inference
- Modern - ESM and CJS support, tree-shakeable
- Fast - Built on koffi, significantly faster than node-ffi
- Safe - Better memory safety than legacy FFI solutions
- Cross-platform - Windows, macOS, Linux support
npm install @modern-ffi/coreimport { Library, types } from '@modern-ffi/core';
// Load a system library and define functions
const libm = new Library('libm', {
ceil: [types.double, [types.double]],
floor: [types.double, [types.double]],
pow: [types.double, [types.double, types.double]],
});
// Call functions directly
console.log(libm.ceil(1.5)); // 2
console.log(libm.floor(1.5)); // 1
console.log(libm.pow(2, 10)); // 1024import { Struct, types } from '@modern-ffi/core';
// Define a C-style struct
const Point = new Struct({
x: types.int,
y: types.int,
});
// Create an instance
const p = Point.create({ x: 10, y: 20 });
console.log(p.x, p.y); // 10 20
// Nested structs
const Rect = new Struct({
topLeft: Point,
bottomRight: Point,
});
const rect = Rect.create({
topLeft: { x: 0, y: 0 },
bottomRight: { x: 100, y: 100 },
});import { FFIArray, TypedArrays, types } from '@modern-ffi/core';
// Fixed-length C array
const IntArray10 = new FFIArray(types.int, 10);
const arr = IntArray10.create([1, 2, 3, 4, 5]);
// TypedArray helpers for numeric data
const { type, create } = TypedArrays.floatArray(1024);
const floatBuffer = create(); // Float32Arrayimport { bindings } from '@modern-ffi/core';
// Automatically find and load native .node addon
const myAddon = bindings('my_addon');import { types, CType } from '@modern-ffi/core';
// Primitive types
types.void // void
types.bool // boolean
types.int8 // signed 8-bit
types.int16 // signed 16-bit
types.int32 // signed 32-bit
types.int64 // signed 64-bit (BigInt in JS)
types.uint8 // unsigned 8-bit
types.uint16 // unsigned 16-bit
types.uint32 // unsigned 32-bit
types.uint64 // unsigned 64-bit (BigInt in JS)
types.float // 32-bit float
types.double // 64-bit float
// C type aliases
types.char, types.uchar
types.short, types.ushort
types.int, types.uint
types.long, types.ulong
types.longlong, types.ulonglong
types.size_t, types.ssize_t
// Pointer and string types
types.pointer // void*
types.string // null-terminated string
types.cstring // C stringimport { Library, createLibrary } from '@modern-ffi/core';
// Create a library wrapper
const lib = new Library('libname', {
functionName: [returnType, [param1Type, param2Type, ...]],
});
// Or use the helper
const lib = createLibrary('libname', {
functionName: [returnType, [paramTypes]],
});
// Call functions
const result = lib.functionName(arg1, arg2);
// Alternative: use .call()
const result = lib.call('functionName', arg1, arg2);
// Close and free resources
lib.close();import { Struct, createStruct } from '@modern-ffi/core';
// Define a struct
const MyStruct = new Struct({
field1: types.int,
field2: types.double,
}, { name: 'MyStruct', pack: 1 }); // optional packing
// Properties
MyStruct.size // total size in bytes
MyStruct.alignment // struct alignment
MyStruct.fields // field names array
MyStruct.offsetOf('field1') // field offset
MyStruct.typeOf('field1') // field type
// Create instances
const instance = MyStruct.create({ field1: 42 });import { FFIArray, createArray, TypedArrays } from '@modern-ffi/core';
// Create array type
const IntArray = new FFIArray(types.int, 10);
// Properties
IntArray.length // array length
IntArray.elementType // element type
IntArray.size // total size in bytes
IntArray.elementSize // single element size
// Create instance
const arr = IntArray.create([1, 2, 3]);
// TypedArray helpers
TypedArrays.int8Array(n) // Int8Array
TypedArrays.uint8Array(n) // Uint8Array
TypedArrays.int16Array(n) // Int16Array
TypedArrays.uint16Array(n) // Uint16Array
TypedArrays.int32Array(n) // Int32Array
TypedArrays.uint32Array(n) // Uint32Array
TypedArrays.int64Array(n) // BigInt64Array
TypedArrays.uint64Array(n) // BigUint64Array
TypedArrays.floatArray(n) // Float32Array
TypedArrays.doubleArray(n) // Float64Arrayimport {
bindings,
hasBindings,
getBindingsPath,
getLibraryName,
getSystemLibraryPaths,
} from '@modern-ffi/core';
// Load native addon
const addon = bindings('my_addon');
const addon = bindings({ name: 'my_addon', searchPaths: ['./lib'] });
// Check if bindings exist
if (hasBindings('my_addon')) { ... }
// Get path without loading
const path = getBindingsPath('my_addon');
// Platform helpers
getLibraryName('foo'); // 'foo.dll' / 'libfoo.dylib' / 'libfoo.so'
getSystemLibraryPaths(); // ['/usr/lib', ...] platform-specificimport { Library, callback, registerCallback, unregisterCallback, types } from '@modern-ffi/core';
// Define callback type
const compareCallback = callback(types.int, [types.pointer, types.pointer]);
// Register a JS function as callback
const myCompare = registerCallback(compareCallback, (a, b) => {
// comparison logic
return 0;
});
// Use in library call
lib.qsort(array, length, elementSize, myCompare);
// Clean up when done
unregisterCallback(myCompare);// Before (ffi-napi)
const ffi = require('ffi-napi');
const libm = ffi.Library('libm', {
'ceil': ['double', ['double']],
});
// After (@modern-ffi/core)
import { Library, types } from '@modern-ffi/core';
const libm = new Library('libm', {
ceil: [types.double, [types.double]],
});// Before (ref-struct-napi)
const StructType = require('ref-struct-napi');
const Point = StructType({
x: 'int',
y: 'int',
});
// After (@modern-ffi/core)
import { Struct, types } from '@modern-ffi/core';
const Point = new Struct({
x: types.int,
y: types.int,
});// Before (bindings)
const bindings = require('bindings');
const addon = bindings('my_addon');
// After (@modern-ffi/core)
import { bindings } from '@modern-ffi/core';
const addon = bindings('my_addon');- Windows (x64, x86)
- macOS (x64, arm64)
- Linux (x64, arm64, arm)
- Node.js >= 18.0.0
MIT