UniFFI: generating Kotlin, Swift, Python and Ruby bindings from one Rust core
a multi-language bindings generator for rust
At a glance
- What is it?
- UniFFI is Mozilla's bindings generator for shipping a Rust library to Kotlin, Swift, Python and Ruby. It is production-used inside Firefox, but the README is explicit that it is far from a 1.0 release and that advanced interfaces can break between upgrades.
- Who is it for?
- Adopt UniFFI when you already have Rust core logic and need it callable from Kotlin, Swift, Python or Ruby without hand-writing an FFI layer per platform; Firefox mobile and desktop are the proof it scales to that. Do not adopt it if your target is C or C++, where the README points at Diplomat and Interoptopus instead, or if you need a stable interface contract, because the project says advanced things can break as you upgrade.
- Can I use it commercially?
- Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem UniFFI solves, and who actually needs it
Writing Rust once and calling it from four languages normally means four hand-written FFI layers. UniFFI replaces those layers with a generator: you describe the interface your Rust code exposes, and the tool produces the glue for each target language. The README frames this as building cross-platform software components in Rust, with the core business logic in Rust and an "object model" describing its interface.
The audience is narrow but real. If your product is an Android app plus an iOS app plus a Python service, and you want one implementation of the parsing, crypto or protocol logic underneath all three, UniFFI is aimed at you. Mozilla is the largest user: the README states UniFFI is used extensively in Firefox mobile and desktop browsers, with functionality written once in Rust and called from Kotlin on Android and Swift on iOS. That is a concrete deployment, not a demo.
It is the wrong tool when your consumer is C or C++. The README lists Diplomat as focused more on C/C++ interop, and Interoptopus alongside it. UniFFI's own supported targets are Kotlin, Swift, Python and Ruby, with C#, Go, Dart, Java, Node and Haskell bindings maintained outside the repository.
How the object model turns into bindings
There are two ways to describe the interface. The first is an interface definition file, written in what the project calls the UniFFI Definition Language (UDL). The second is proc-macros applied directly to Rust code, documented under the proc-macro chapter of the user guide. Both describe the same thing: the set of functions, types and callbacks that cross the boundary.
From that description UniFFI does two jobs. It compiles your Rust code into a shared library for the target platforms, and it generates bindings that load and use that library from the foreign language. The workspace layout reflects the split: uniffi_udl and weedle2 handle the UDL parsing, uniffi_macros and uniffi_meta handle the proc-macro path, uniffi_bindgen holds the generation logic, and uniffi_core sits underneath. There is also a separate uniffi-bindgen-kotlin-jni crate, so the Kotlin path has a JNI-specific component rather than going through the same generic mechanism as Swift and Python.
The generated code is not a thin wrapper. Because the object model has to survive the trip, the repository carries dedicated bindgen-tests directories for Kotlin, Python, Ruby and Swift, including narrow cases such as keywords, enum payload clashes, dictionary nesting and Swift bridging-header compilation. Those test suites exist because name collisions and type mapping are where a generator breaks, not in the happy path.
Installing UniFFI and generating your first bindings
The README does not give a cargo install line; it points at the user guide and at the examples directory, and the examples are the practical starting point. The workspace includes an examples/app/uniffi-bindgen-cli crate, and the examples README describes the sample components. The simplest complete component in the tree is examples/arithmetic, with examples/arithmetic-procmacro as its proc-macro twin.
Start by cloning the repository and building the workspace, which also builds the example components:
cargo buildThen move into the arithmetic example and run it. The examples are structured so each one can be executed directly; the README's pointer to examples/arithmetic is the entry point for seeing a UDL-defined interface work end to end.
cd examples/arithmetic
cargo runWhat you should see is the example's own output, not a UniFFI banner: the arithmetic component exercises the generated bindings. To generate bindings for your own crate, the user guide's UDL file spec and proc-macro chapters are the two documented paths, and the bindgen-tests directories show the shape of the output for each language. The repository does not document a single canonical generation command in the README, so treat the guide as the source of truth for the exact invocation.
The pre-1.0 warning is the real constraint
The README says UniFFI is considered ready for production use, and then in the same paragraph says it is a long way from a 1.0 release with lots of internal work still going on. It adds that simple consumers are unlikely to break, but more advanced things might break as you upgrade.
That is an unusually honest statement and it should drive your adoption decision more than any feature list. A component that exposes a handful of functions over primitives is in the safe zone. A component that leans on callbacks, async, custom types, remote types or trait objects is in the zone the README is warning about, and the examples directory has a separate sample for each of those (callbacks, futures, custom-types, remote-types, traits, async-api-client). The breadth of the examples is a map of the surface area that can move under you.
There is no published migration guide in the README, and no rollback procedure is documented there. If your release process cannot absorb a generated-binding change that requires edits on the Kotlin or Swift side, that is a reason to wait or to pin aggressively.
Diplomat and Interoptopus take a different route
The README names two alternatives and is specific about one of them: Diplomat is "focused more on C/C++ interop". That single sentence is the whole comparison the project offers, and it is enough to make the choice concrete. If your consumers are C or C++ libraries rather than Kotlin, Swift, Python or Ruby applications, Diplomat's centre of gravity is where you are, and UniFFI's is not.
Interoptopus is listed without a qualifier. Both alternatives exist because the same shape of problem (Rust core, foreign callers) admits different answers, and the difference that matters here is which foreign languages the generator treats as first-class. UniFFI's first-class set is Kotlin, Swift, Python and Ruby. C#, Go, Dart, Java, Node and Haskell are third-party bindings maintained in other repositories, which means their release cadence and their support burden sit with those maintainers, not with Mozilla.
Maintenance, licence and what an upgrade costs
The repository is not archived and the last push was on 2026-09-18, five days before this writing, so the codebase is being touched. That says nothing about the stability of the generated interface, which is the thing the README warns about; a project can be actively pushed to and still change its bindings in ways that require consumer edits.
UniFFI is licensed under MPL-2.0. The file-level copyleft in MPL-2.0 applies to modified covered files, which matters if you fork the generator or patch uniffi_bindgen rather than merely consuming its output. This is not legal advice; if you plan to modify the generator and redistribute it, get your own reading of the licence.
The upgrade cost is concentrated in the generated code. Because Kotlin, Swift, Python and Ruby output is produced from your UDL or proc-macro annotations, a change in the generator can change the foreign-language API surface, and that shows up as a diff in files you may have committed. CHANGELOG.md at the top level of the repository is where release-by-release notes would live.
Editorial conclusion
Adopt UniFFI when you already have Rust core logic and need it callable from Kotlin, Swift, Python or Ruby without hand-writing an FFI layer per platform; Firefox mobile and desktop are the proof it scales to that. Do not adopt it if your target is C or C++, where the README points at Diplomat and Interoptopus instead, or if you need a stable interface contract, because the project says advanced things can break as you upgrade. Verify first that your types survive the object-model conversion: read the UDL file spec or the proc-macro chapter in the user guide, then build one of the examples under examples/ and inspect the generated Kotlin or Swift before committing your real crate.
Frequently asked questions
What is UniFFI in Rust?
It is a multi-language bindings generator. You write core logic in Rust, describe its interface in a UDL file or with proc-macros, and UniFFI compiles the Rust into a shared library and generates bindings so Kotlin, Swift, Python or Ruby code can call it.
Which languages does UniFFI support out of the box?
The README lists Kotlin, Swift, Python and Ruby as supported, with third-party bindings available for C# and Golang. Bindings for Dart, Java, Node and Haskell are also listed as maintained outside the main repository.
Is UniFFI stable enough for production?
The README says it is considered ready for production use but is a long way from a 1.0 release. It states that simple consumers are unlikely to break, while more advanced things might break as you upgrade.
How do I try UniFFI without setting up my own crate?
The README points at the examples directory, and the workspace includes several example components such as examples/arithmetic and examples/arithmetic-procmacro. Building the workspace with cargo build and running an example is the shortest path to seeing generated bindings work.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mozilla-uniffi-rs)