BoltFFI

August 4, 2026 ยท View on GitHub

A high-performance multi-language bindings generator for Rust. Up to 1,000x faster than UniFFI. Up to 450x faster than wasm-bindgen.

Join our Discord

Quick links: User Guide | Tutorial | Getting Started

Performance

vs UniFFI (Swift/Kotlin)

BenchmarkBoltFFIUniFFISpeedup
noop<1 ns1,416 ns>1000x
echo_i32<1 ns1,416 ns>1000x
counter_increment (1k calls)1,083 ns1,388,895 ns1,282x
generate_locations (1k structs)4,167 ns1,276,333 ns306x
generate_locations (10k structs)62,542 ns12,817,000 ns205x

vs wasm-bindgen (WASM)

BenchmarkBoltFFIwasm-bindgenSpeedup
1k particles29,886 ns13,532,530 ns453x
100 particles3,117 ns748,287 ns240x
1k locations21,931 ns4,037,879 ns184x
1k trades42,015 ns5,781,767 ns138x
100 locations2,199 ns283,753 ns129x

Full benchmark code: benchmarks

Why BoltFFI?

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.

What it does

Mark your Rust types with #[data] and functions with #[export]:

use boltffi::*;

#[data]
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 sources

Use it from Swift, Kotlin, Java, C#, TypeScript, or Python.

let d = distance(a: Point(x: 0, y: 0), b: Point(x: 3, y: 4)) // 5.0
val d = distance(a = Point(x = 0.0, y = 0.0), b = Point(x = 3.0, y = 4.0)) // 5.0
double d = MyLib.distance(new Point(0.0, 0.0), new Point(3.0, 4.0)); // 5.0
double d = MyLib.Distance(new Point(0.0, 0.0), new Point(3.0, 4.0)); // 5.0
import { distance } from 'your-crate';
const d = distance({ x: 0, y: 0 }, { x: 3, y: 4 }); // 5.0
import your_crate
d = your_crate.distance(your_crate.Point(0, 0), your_crate.Point(3, 4))  # 5.0

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.

Supported languages

LanguageStatus
SwiftFull support
KotlinFull support
JavaFull support
C#Full support
WASM/TypeScriptFull support
CPartial
PythonFull support
C++Planned
RubyPlanned
DartIn progress
ScalaPlanned
GoPlanned
LuaPotential
RPotential

Want another language? Open an issue.

Installation

cargo install boltffi_cli

Prebuilt 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 boltffi

Configure the crate type in Cargo.toml:

[lib]
crate-type = ["cdylib", "staticlib"]

Documentation

Alternative tools

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

Contributing

If this tool sounds interesting to you, please help us develop it. You can:

License

BOLTFFI is released under the MIT license. See LICENSE for more information.