# uniffi-bindgen-react-native: one Rust crate, TypeScript on mobile, web and Node

> uniffi-bindgen-react-native generates TypeScript bindings from Rust annotated with UniFFI macros, and reaches React Native through JSI, the web through WASM and Node through N-API. The name is now wrong, since the tool no longer targets React Native alone, and the packages are being renamed around an @ubjs scope.

**jhugman/uniffi-bindgen-react-native** — Make React-Native Turbo Modules out of Rust

- Repository: https://github.com/jhugman/uniffi-bindgen-react-native
- Website: https://jhugman.github.io/uniffi-bindgen-react-native/
- Stars: 556 · Forks: 76
- Language: Rust
- License: NOASSERTION
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/jhugman-uniffi-bindgen-react-native

## Three hosts, one set of annotations

uniffi-bindgen-react-native is a tool that generates TypeScript bindings for Rust code, making it usable in React Native apps, web pages, and Node.js. It builds on UniFFI, Mozilla's bindings generator ecosystem.

The pitch is that you write your business logic once in Rust and access it directly from TypeScript, whether you are developing for mobile platforms, the web or servers. UniFFI provides procedural macros to describe your API, prioritising expressivity and memory safety, and the README connects that to portability.

The three hosts are reached by different mechanisms, and that is the part that matters architecturally. For React Native there is a JSI C++ layer to call Rust from TypeScript and back again, plus a Turbo-Module that installs the bindings into a running React Native library. For web pages there is a WASM binding crate. And for Node.js there is the @ubjs/node N-API runtime, which loads your compiled Rust cdylib at runtime.

All of them use the same proc macros. You annotate your Rust once, and build for Android, iOS, the web and Node.js.

The project is led by James Hugman, with deep collaboration from the Filament engineering team, and funded by Filament, Mozilla and Livekit. The licence is MPL-2.0, the primary language is Rust, and the last push was on 2026-10-15.

## The FFI surface it supports, listed explicitly

JavaScript hosts the Rust library, and the tool and UniFFI facilitate the communication between the two. The README enumerates the kinds of crossing that are supported, and the list is specific enough to be useful when you are deciding whether your API shape will work.

There is same thread calling across the FFI from JavaScript to Rust, and async calls from JavaScript to Rust. In the other direction there are same thread callbacks from Rust to JavaScript and async callbacks from Rust to JavaScript. Values can be passed by reference, for objects, and by value, for records. And the type system includes enums and tagged unions.

The distinction between objects and records is the one to be careful with. A record is passed by value, so it is copied across the boundary. An object is passed by reference, so it is a handle to something living on the other side, and the calling convention for it differs. If your Rust API mixes the two, the generated TypeScript will too, and the types will tell you which is which.

The async support in both directions is what makes the tool usable for anything that touches a network or a database, since a blocking Rust call would stall the JavaScript event loop.

The repository has example directories that correspond to these features, including an arithmetic example, a callbacks example, a custom-types example, a futures example, and a rondpoint example, each of which also has a procmacro variant, so the difference between the macro and the non-macro style of writing the same component is visible in the tree.

## The comparison with wasm-bindgen is about annotation reuse

The README has a section asking why use uniffi-bindgen-react-native instead of wasm-bindgen, and the answer is a specific technical point rather than a claim about quality.

uniffi-bindgen-react-native generates a wasm-bindgen crate from uniffi annotations. And when you come to use your Rust crate in another context, say from Python, or Kotlin, or React Native, then you can generate FFIs for those platforms, all with the same uniffi annotations.

So the argument is that the annotation is the asset. You describe your API once with UniFFI macros, and each target's binding generator consumes that same description. With wasm-bindgen alone, the wasm-bindgen specific attributes are the API description, and a second platform would need a second set of attributes, which means the two descriptions can drift apart.

The trade is that you are tied to the UniFFI annotation vocabulary. If a feature is expressible only through wasm-bindgen specifics, this route will not carry it.

The two reasons the project gives for existing are on that theme. Spend more time writing TypeScript and Rust, less time hand-writing FFIs, and your Rust SDK is portable across multiple languages.

The prior art is acknowledged too, with a link to cawfree/react-native-webassembly, and the project is now the one with the WASM support built in, which is what makes the comparison question interesting rather than rhetorical.

## Three npm packages, and a rename in progress

The Packages section is short and describes a restructuring that is currently under way, which matters if you are pinning versions or reading generated code.

The uniffi-bindgen-react-native package on npm provides the CLI, whose binary is ubrn, the tooling, and the legacy-named runtime that older generated code imports from.

The @ubjs/core package has the same runtime bytes under a new identity, and new generated code imports from here.

The @ubjs/node package is the N-API runtime backend, required for Node and Bun consumers of generated bindings.

The key features section then breaks the hosts down again with the mechanism for each: React Native with JSI C++ to call Rust from TypeScript and back again, and a Turbo-Module that installs the bindings into a running React Native library; web pages with a WASM binding crate; and Node.js with the @ubjs/node N-API runtime, loading your compiled Rust cdylib at runtime.

The Notice section explains the renaming. Now that uniffi-bindgen-react-native supports WASM, the React Native name no longer seems appropriate, and in the near future the name will change to uniffi-bindgen-javascript, with backwards compatibility ensured.

So there are two migrations running at once in the package names. The runtime moved from the legacy name to the @ubjs scope, and the whole project is about to be renamed. Backwards compatibility is promised for the rename, but a project mid-rename is a project where you should read the changelog before bumping.

## The build is a Cargo workspace with a JavaScript half

The repository layout shows a Rust workspace that also contains a TypeScript package, and the manifest is where the two are wired together.

The Cargo workspace has members covering crates/, examples/, fixtures/, the runtimes/ directory, the wasm helper crate, and an xtask. The wasm runtime directory is excluded from the workspace, which is the usual arrangement for a crate that is built for the web target rather than the host. The resolver is version 2.

The workspace dependencies pin the UniFFI family tightly. uniffi, uniffi_bindgen, uniffi_core and uniffi_meta are all pinned with the equals operator to 0.31, which is the right call for a tool that reads a foreign-function-interface schema: a UniFFI minor bump can change the generated output, and a tool that generates code from annotations has to move with them together.

The npm side is a plain TypeScript package. The name is uniffi-bindgen-react-native at version 0.31.0-6, the type is module, and the exports map provides both ESM and CommonJS entry points with the types alongside. Two binaries are declared, ubrn and uniffi-bindgen-react-native, both pointing at the same CLI file.

The scripts are short. The build changes into the typescript directory and runs npm install and npm run build, prepare runs yarn build, and the test script is cargo test, which is a reminder that the test suite is on the Rust side. The dev dependencies include metro and metro-core, which is the React Native bundler, plus prettier, tsx and typescript.

The package manager is pinned to yarn 1.22.22 with a hash, and there is a .licence-config.yaml alongside the source-licenser dev dependency, which is how the MPL headers are applied across the mixed-language tree.

## Who is using it, and what the compatibility matrix implies

The README lists who is using the tool, and the entries are more informative than a logo wall because each one names a use.

The @unomed/react-native-matrix-sdk is a package built on it. ChessTiles on iOS uses it so that the team can run their performance critical solution search algorithm and business logic in Rust while rapidly prototyping the UI with React Native, which is the canonical reason to adopt a Rust bridge. The @fressh/react-native-uniffi-russh package is a React Native binding for an SSH library, which is a good example of bringing an existing Rust codebase to a mobile app. And there is Whip on iOS and on Android.

The two Matrix products, one of them a React Native SDK and the other an app, are worth noting because they show the tool used in both directions, as a library dependency and as the bridge inside a shipped app.

The badges at the top of the README show the testing setup, and the third one is the interesting one. There is a CI badge, a compatibility badge for a nightly matrix, and a compatibility badge described as a PR gate. So the project runs a compatibility matrix against something that moves, on a schedule, and blocks pull requests that break it. That is the right shape for a binding generator, because the thing it has to stay compatible with is a set of upstream projects rather than a fixed target.

The docs site is at jhugman.github.io/uniffi-bindgen-react-native, with a step-by-step tutorial for making a Rust turbo-module and running it in a web page with WASM, and there is a separate Node.js reference page.

## Conclusion

Adopt uniffi-bindgen-react-native if you want to write business logic once in Rust and call it from TypeScript on mobile, on the web and on Node, and you are willing to depend on a tool that is mid-rename. Do not adopt it expecting a stable package identity, because the README says the name will change to uniffi-bindgen-javascript with backwards compatibility ensured, and the runtime is being moved to a new @ubjs scope. Before you start, read the packages section, because the choice between the legacy runtime name and the new one is what determines which import your generated code produces.

## FAQ

### What does uniffi-bindgen-react-native generate?

It generates TypeScript bindings from Rust code, so the Rust can be called from React Native apps, web pages and Node.js. It builds on UniFFI, Mozilla's bindings generator ecosystem, and the same proc macros are used for every target, so you annotate the Rust once and build for Android, iOS, the web and Node.js.

### Which npm packages does the tool publish?

Three. uniffi-bindgen-react-native provides the CLI named ubrn, the tooling and the legacy-named runtime that older generated code imports from. @ubjs/core has the same runtime bytes under a new identity and is what new generated code imports. @ubjs/node is the N-API runtime backend, required for Node and Bun consumers.

### How does uniffi-bindgen-react-native differ from wasm-bindgen?

It generates a wasm-bindgen crate from uniffi annotations, and the same uniffi annotations can then be used to generate FFIs for other platforms such as Python, Kotlin or React Native. The trade is that the API description is tied to the UniFFI annotation vocabulary rather than to wasm-bindgen attributes.

### Is uniffi-bindgen-react-native being renamed?

Yes. The README says that since the tool now supports WASM, the React Native name no longer seems appropriate, and that the name will change to uniffi-bindgen-javascript in the near future, with backwards compatibility ensured.

## Sources

- [Issues](https://github.com/jhugman/uniffi-bindgen-react-native/issues)
- [jhugman/uniffi-bindgen-react-native on GitHub](https://github.com/jhugman/uniffi-bindgen-react-native)
- [Project website](https://jhugman.github.io/uniffi-bindgen-react-native/)
- [README](https://github.com/jhugman/uniffi-bindgen-react-native/blob/main/README.md)
- [Releases](https://github.com/jhugman/uniffi-bindgen-react-native/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jhugman-uniffi-bindgen-react-native
