A high-performance multi-language bindings generator for Rust. Up to 1,000x faster than UniFFI. Up to 450x faster than wasm-bindgen.
Quick links: User Guide | Tutorial | Getting Started
| Benchmark | BoltFFI | UniFFI | Speedup |
|---|---|---|---|
| noop | <1 ns | 1,416 ns | >1000x |
| echo_i32 | <1 ns | 1,416 ns | >1000x |
| counter_increment (1k calls) | 1,083 ns | 1,388,895 ns | 1,282x |
| generate_locations (1k structs) | 4,167 ns | 1,276,333 ns | 306x |
| generate_locations (10k structs) | 62,542 ns | 12,817,000 ns | 205x |
| Benchmark | BoltFFI | wasm-bindgen | Speedup |
|---|---|---|---|
| 1k particles | 29,886 ns | 13,532,530 ns | 453x |
| 100 particles | 3,117 ns | 748,287 ns | 240x |
| 1k locations | 21,931 ns | 4,037,879 ns | 184x |
| 1k trades | 42,015 ns | 5,781,767 ns | 138x |
| 100 locations | 2,199 ns | 283,753 ns | 129x |
Full benchmark code: benchmarks
Serialization-based FFI is slow. UniFFI serializes every value to a byte buffer. wasm-bindgen materializes every struct as a JavaScript object. That overhead shows up even when you're making tens or hundreds of FFI calls per second.
BoltFFI uses zero-copy where possible. Primitives pass as raw values. Structs with primitive fields pass as pointers to memory both sides can read directly. WASM uses a wire buffer format that avoids per-field allocation. Only strings and collections go through encoding.
Mark your Rust types with #[data] and functions with #[export]:
use boltffi::*;
#[data]
#[derive(Clone, Copy)]
pub struct Point {
pub x: f64,
pub y: f64,
}
#[export]
pub fn distance(a: Point, b: Point) -> f64 {
let dx = b.x - a.x;
let dy = b.y - a.y;
(dx * dx + dy * dy).sqrt()
}Run BoltFFI for the targets you need:
boltffi pack all
# Produces: ./dist/apple/YourCrate.xcframework + Package.swift
# Produces: ./dist/android/jniLibs/<abi>/libyour_crate.so + Kotlin bindings
# Produces: ./dist/java/native/<host-target>/libyour_crate_jni.* + Java bindings
# Produces: ./dist/wasm/pkg/*.wasm + TypeScript bindings + npm package
# Produces: ./dist/csharp/packages/*.nupkg with RID native assets
# Produces: ./dist/python/wheelhouse/*.whl with Python package sourcesUse it from Swift, Kotlin, Java, C#, TypeScript, Python, or C.
let d = distance(a: Point(x: 0, y: 0), b: Point(x: 3, y: 4)) // 5.0val d = distance(a = Point(x = 0.0, y = 0.0), b = Point(x = 3.0, y = 4.0)) // 5.0double d = MyLib.distance(new Point(0.0, 0.0), new Point(3.0, 4.0)); // 5.0double d = MyLib.Distance(new Point(0.0, 0.0), new Point(3.0, 4.0)); // 5.0import { distance } from 'your-crate';
const d = distance({ x: 0, y: 0 }, { x: 3, y: 4 }); // 5.0import your_crate
d = your_crate.distance(your_crate.Point(0, 0), your_crate.Point(3, 4)) # 5.0For C, enable [targets.c] in boltffi.toml, then run boltffi pack c --experimental --deny-skipped. A package named mylib exposes:
#include "mylib.h"
int main(void) {
MylibPoint start = {0.0, 0.0};
MylibPoint end = {3.0, 4.0};
return mylib_distance(start, end) == 5.0 ? 0 : 1;
}The C package includes CMake targets and pkg-config files for shared and static linking. See C linking and memory management for CMake, Make, Meson, and ownership rules, or run the C demo.
The generated bindings use each language's idioms. Swift gets async/await. Kotlin gets coroutines. Java gets CompletableFuture and functional interfaces. C# gets Tasks and async enumerables. TypeScript gets Promises. Errors become native exceptions in the managed targets. C uses typed results and explicit cleanup functions.
| Language or target | Status |
|---|---|
| Swift | Full support |
| Kotlin | Full support |
| Kotlin Multiplatform | Experimental, JVM and Android |
| Java | Full support |
| C# | Full support |
| WASM/TypeScript | Full support |
| C | Experimental, synchronous APIs |
| Python | Full support |
| C++ | Planned |
| Ruby | Planned |
| Dart | In progress |
| Scala | Planned |
| Go | Planned |
| Lua | Potential |
| R | Potential |
Want another language? Open an issue.
Kotlin Multiplatform generates a shared commonMain API with jvmMain and androidMain implementations, it currently supports synchronous infallible free functions using booleans, signed integers and floating point values, including Rust parameter defaults
Enable it in boltffi.toml
[targets.kotlin_multiplatform]
enabled = trueGenerate the bindings or package them with the native libraries
boltffi generate kmp --experimental
boltffi pack kmp --experimentalUnsupported APIs fail generation, Kotlin/Native targets such as iOS and macOS are not supported yet
cargo install boltffi_cliPrebuilt CLI archives are also attached to each GitHub release. Each archive has a matching .sha256 checksum file. For Windows ARM64, download boltffi-windows-arm64.zip and boltffi-windows-arm64.zip.sha256.
Add BoltFFI to your library crate:
cargo add boltffiConfigure the crate type in Cargo.toml:
[lib]
crate-type = ["cdylib", "staticlib"]Other tools that solve similar problems:
- UniFFI - Mozilla's binding generator, uses serialization-based approach
- Diplomat - Focused on C/C++ interop
- cxx - Safe C++/Rust interop
If this tool sounds interesting to you, please help us develop it. You can:
- View the contributor guide.
- File or work on issues here on GitHub.
- Join discussions on Discord.
BOLTFFI is released under the MIT license. See LICENSE for more information.
