BoltFFI

BoltFFI is a tool that generates foreign-language bindings from Rust libraries. It fits the practice of consolidating business logic in a single Rust library while targeting multiple platforms, making it simpler to develop and maintain a cross-platform codebase. BoltFFI helps you ship a Rust library to any platform: run boltffi pack and get ready-to-use native libraries and bindings. The generated wrappers handle type conversion, memory management, and error propagation across the language boundary.

The generated bindings are native code that uses each language’s idioms. Swift bindings use structured concurrency with async/await. Kotlin bindings use coroutines. TypeScript bindings use Promises and integrate with WASM. Errors become native exceptions. Types map to their platform equivalents. The result is code you can use natively, without dealing with pointers or manual memory management.

BoltFFI uses a zero-copy approach where possible. Primitives and structs containing only primitives pass across the boundary without serialization. Complex types like strings and collections use a wire format.

BoltFFI architecture diagram
RustSource
use boltffi::*;

#[data]
pub struct Point {
  pub lat: f64,
  pub lng: f64,
}

#[export]
pub fn distance(from: Point, to: Point) -> f64 {
  let dlat = to.lat - from.lat;
  let dlng = to.lng - from.lng;
  (dlat * dlat + dlng * dlng).sqrt()
}
// Generated Swift
public struct Point {
  public var lat: Double
  public var lng: Double
}

func distance(from: Point, to: Point) -> Double

// Usage
let d = distance(from: a, to: b)

How it works

  1. Add boltffi as a dependency
  2. Mark types with #[data] and functions with #[export]
  3. Run boltffi pack apple, boltffi pack android, or boltffi pack wasm
  4. Import the generated framework in your project

The generated bindings use native idioms. Swift gets async/await and throwing functions. Kotlin gets coroutines and sealed classes. TypeScript gets Promises and typed interfaces. Your Rust library feels like a native SDK.

Performance

Primitives pass as raw values. Structs with primitive fields pass as pointers. Only strings and nested collections go through encoding.

Benchmarks on Apple Silicon, compared to UniFFI (Swift/Kotlin):

OperationBoltFFIUniFFISpeedup
Primitive (i32, f64)<1 ns625 ns
Small string42 ns1,958 ns47x
1,000 structs1,958 ns1,195,354 ns611x
10,000 i32 values1,291 ns1,991,146 ns1,542x

Compared to wasm-bindgen (TypeScript):

OperationBoltFFIwasm-bindgenSpeedup
Primitive (i32, f64)2 ns2 nstie
1k string806 ns2,921 ns3.6x
1,000 structs (6 fields)21,931 ns4,037,879 ns184x
1,000 structs (10 fields)29,886 ns13,532,530 ns453x

Full benchmark code: bench_demo.

Supported languages

BoltFFI has full support for Swift, Kotlin, and TypeScript (WASM). All features documented in this manual work for all three languages. Adding support for more languages is in progress.

LanguageStatus
SwiftSupported
KotlinSupported
TypeScript (WASM)Supported
PythonIn progress
C#In progress

If you want a language added or considered, open an issue.

What you can export

  • Primitives, strings, structs, enums, Option, Result, Vec, HashMap
  • Sync and async functions
  • Closures and callback traits
  • Classes with methods
  • Async streams
  • Rust errors as exceptions

See Types for the full mapping, or Getting Started to set up a project.