Comparing Benchmark Performance of Mobile Multiplatform Tools

I’ve built a lot of mobile apps, most recently using multiplatform development tools. I started multiplatform with React Native (RN), which was a popular tool at the time that also shared the same language I was using for the backend, i.e. TypeScript. I still maintain RN production app code today. With the emergence and maturing of Kotlin Multiplatform (KMP) I returned to my Android development roots to use its own mobile multiplatform offering – KMP combined with Compose Multiplatform (CMP). KMP initially was useful only for sharing business logic across mobile platforms, but now with CMP becoming stable on iOS, it’s become a viable alternative for complete production apps. It is a fast-growing contender for multiplatform development, more than doubling its market share in 2025.

For any greenfield apps - particularly ones which share a lot of common UI across mobile & desktop & web apps - I prefer KMP/CMP now (for brevity’s sake let’s call it AMP – Android Multiplatform.) I have legacy React Native apps in production, so I’ve asked myself is it worth considering porting an RN app over to AMP on the next major release? On paper I’d expect AMP to perform better. But would the effort of re-writing an RN app (even with the help of AI) be worth the app performance boost? A marginal performance difference would not be worth it. I needed to compare the tools, to get some actual benchmark performance data.

AI for Benchmark Apps

Before AI coding tools, the time needed for me to hand-code a number of Proof of Concept apps across different platforms would have been prohibitive, so I wouldn’t have been able to do this benchmark comparison. One of the benefits of AI coding assistants is that they can generate “throwaway” benchmarking apps to test exactly this kind of thing, and do it quickly and cheaply.

I asked Claude Code to generate equivalent functioning apps using 3 multiplatform tools – React Native, KMP/CMP, & Flutter. I included Flutter because at the time of writing it is actually the most popular multiplatform tool used by production apps (at 46%, vs. 35% for RN, and 18% for KMP.)

I only wanted to test the relative performance of the two basic aspects of MP platforms where I know major inefficiencies and differences exist between the tools. Firstly, I wanted to check how long a call to the native layer would take. In RN, despite New Architecture improvements and the use of Codegen for Turbo Module integration, there is still an overhead for Javascript usage. I passed a reasonable size piece of data to test the marshalling – a 1000 element array, sorted in the native call by the native platform’s available sorting technique.

Secondly, I wanted a rudimentary indication of the difference in performance in UI rendering. In a UI-heavy app, this benchmark would be a crucial deciding factor. Note that it is hard to get the different MP tools to do an entirely equivalent render delta test here as they have to use different API calls for it (requestAnimationFrame, withFrameNanos, addPostFrameCallback.) So the UI results should only be taken as an indicative comparison, rather than actual reliable render times. Running the render test multiple times (1000) and averaging the result across them helps to smooth out some of the anomalies.

Running the Test

Claude built Android & iOS builds for the three multiplatform tools, which I ran to get the benchmark figure results below. There are a few important things to note about how the tests were run:

  • Release builds were used, not Debug builds, to better reflect actual app running conditions and remove performance overheads of debug mode logging, etc.

  • The apps were run on actual hardware devices, not simulators. Again, simulators would not allow for real-world production runtime conditions. For example, Flutter can only run Debug builds on a simulator, not a release build. There can also be differences in performance between Android and iOS simulator devices (for example ReactNative UI rendering can be nearly 3 times slower on an Android emulator than a physical Android device.)

  • Equivalent performing hardware across Android & iOS were not used. While I did use older devices to ensure the results would be representative of running on minimum supported, less performant, mobile OS versions, the hardware used could not be guaranteed to be equivalent across Android & iOS. For this test, the most important thing is to compare how the different tools perform on the same device & OS.

  • The result figure was taken after running 3 or 4 iterations of the test, to minimize the effects and difference of things like startup load times, caching, etc.

Here’s a screenshot of the 3 different app builds (running on Android):

MPCompExt

The Numbers

Platform Native Layer Call
Avg. (ms)
Screen Re-Render
Avg. (ms)
Android RN 2.68 13.1
Android AMP 0.49 10.31
Android Flutter 2.08 14.25
iOS RN 2.7 13.36
iOS AMP 0.45 8.73
iOS Flutter 3.54 13.02

The Findings

  1. AMP is a clear performance winner, which is as expected. Its native call was over 4 times faster than RN's or Flutter's. This is expected because KMP’s expect/actual mechanism is directly compiled and it does not use marshalling or serialization to the native layer across a runtime boundary like RN's Turbo Module and Flutter's platform channel do.

  2. UI rendering is faster on AMP, by over one third. Compose's recomposition mechanism would seem to have the edge over RN Hermes/Fabric or Flutter’s Impeller too.

  3. AMP is (surprisingly) good on iOS as well as Android. Given that Kotlin & Compose came originally from their home on Android, it is a surprising result (to me) to see that on this simple equivalence test they actually performed slightly better on iOS than Android (although any hardware disparities have to be considered here)!

Caveats & Omissions

Some words of caution about these results: this was a very specific and rudimentary exercise to test certain conditions, and can’t be considered a definitive or highly accurate gauge of performance characteristics on the platforms. There are many factors not tested by this exercise. How the results should be considered depends very much on the type of app using them.

For example, if the app was structured with a lot of frequent, fine-grained calls to the native layer, that performance result metric above might be quite critical to the overall performance of your app. However if your app only does one or two basic native calls during a session, it’s probably not going to affect your app too much.

Other factors that were not measured or considered in the test are startup times (e.g. loading Turbo Modules) and memory usage which can be considerably larger on RN & Flutter (though recent versions have improvements that address exactly these kind of issues).

The UI re-render metric is for a very simple screen. Complex UIs and Animations would need more detailed testing, and would depend on how well the UI code is written for the chosen multiplatform tool, i.e. effective use of memoization in RN, and for Compose best practices to avoid unnecessary recomposition (such as using Stable or Derived State objects).

While not a perfect test, it serves adequately to highlight the relative performances of basic multiplatform essential functionality. If in doubt, or if you’d like to customize your own benchmark test, the source code is available to use.

The Conclusion – to port or not to port?

Is it worth porting a legacy React Native app to KMP/CMP code?

Well .. it depends!

On performance indicators alone, it certainly seems worthwhile. KMP to Native calls are significantly better (over 4 times faster) than the equivalent in RN (or Flutter). Even UI rendering in CMP would appear to be quicker (by about one third), and certainly no slower than the competition.

The overall decision is more complex though, needing to consider the following too: the frequency of native calls made by the app; the complexity of the UI and whether animations are widely used; the amount of UI code to be re-written and tested (and how AI coding tools could be engaged to support this); and the maturity of the ecosystem provided by the multiplatform tool (i.e. how many Expo/React libraries are used by the app and do mature Kotlin equivalents exist yet).

There’s a lot to consider for any particular app, but overall this test does give me confidence that – on performance alone – KMP/CMP is the future of multiplatform development, and as of CMP version 1.8+ it is certainly a more than worthy replacement for RN mobile apps which, in spite of its long track record and all the improvements made to it over those years, still hasn’t garnered enough confidence from its own developers needed to promote it to version 1.0!