A react-native (or actually; Expo) app that compares react-native's Turbo Modules vs expo's Expo Modules vs @mrousavy's Nitro Modules.
This app specifically benchmarks the time it takes to call a synchronous function and return a result back to JS.
There are two synchronous functions per module:
addNumbers(a: number, b: number): number
addStrings(a: string, b: string): string
For each module, I chose the recommended language for iOS - so the TurboModule is implemented in Objective-C, and both the Expo Module and Nitro Module are implemented in Swift.
The functions are run 100.000 times after a short timeout to make sure the JS VM isn't busy with any other scheduled microtasks, and the total execution time is measured with performance.now()
.
Nitro is an upcoming library/toolkit I have been working on because I hit a lot of limitations with my libraries (react-native-vision-camera, react-native-mmkv, react-native-filament, and so on).
I will use Nitro in my libraries to allow me to make them much faster than they already are, and to benefit from some fundamental differences such as it's instance-based approach. The Frame
in VisionCamera, or MMKV
in MMKV, or anything in Filament are all a C++ objects - I needed a better way of exposing those to JS, so I built Nitro.
I will make Nitro publicly available for everyone to build native C++, Swift or Kotlin modules with! 🔥
On my iPhone 15 Pro I got these numbers in a release build:
ExpoModules | TurboModules | NitroModules | |
---|---|---|---|
100.000x addNumbers(...) |
434.85 | 115.86ms | 7.27ms |
100.000x addStrings(...) |
429.53ms | 179.02ms | 29.94ms |
- For
addNumbers(...)
, Nitro Modules is 59x as fast as ExpoModules, and 15x as fast as TurboModules 🔥 - For
addStrings(...)
, Nitro Modules is 13x as fast as ExpoModules, and 5x as fast as TurboModules 🔥
On my Mac Studio (Apple M1 Max, 32GB RAM), I got these numbers in a release build ("designed for iPad"):
ExpoModules | TurboModules | NitroModules | |
---|---|---|---|
100.000x addNumbers(...) |
764.31ms | 195.12ms | 42.32ms |
100.000x addStrings(...) |
773.00ms | 308.65ms | 138.43ms |
Note that these are just very specific benchmarks. They profile JS <-> Native function execution time (call, argument parsing, and result argument conversion). In an actual real world app, performance may vary.
Note: I put these benchmarks together in ~1 hour. My focus is on making Nitro Modules as fast as possible, but also as powerful as possible, so this is where my time is dedicated at. If I made any mistakes in the benchmark, please let me know so I can update it asap!
I don't intend to put Turbo or Expo modules in bad light here, they are insanely cool tools to build native modules.