We have shipped mobile apps in Swift, Kotlin, Flutter, and React Native. There is no universally best answer, but for the class of app most of our clients need to build, React Native wins the most often. Here is the honest breakdown.
The apps we build are usually forms, lists, API calls, authentication, notifications, and some reporting. Line-of-business apps. Not games. Not real-time graphics. Not heavy audio or video processing. For that category, the performance delta between React Native and native is invisible to users. The maintenance delta, on the other hand, is substantial.
Maintenance is the killer for native. You are managing two codebases in two languages with two IDEs and two release processes. Every feature gets built twice. Every bug fix gets shipped twice. Every design change gets reviewed twice. The engineering overhead is roughly double, and the teams that justify that overhead usually have apps where the native performance actually matters.
Our post on native vs cross-platform has the full decision tree. The short version: if the app is genuinely performance-critical or deeply tied to platform-specific features, go native. If it is a normal business app, go React Native and save the operational tax.
The other reason React Native wins is hiring. Most modern frontend teams already know React. Going to React Native is a smaller jump than learning Swift or Kotlin from scratch. For a business that needs to build mobile but does not have a dedicated mobile team yet, React Native is the path with the shortest ramp.
Expo specifically is the ecosystem we reach for first in most projects. It handles the native toolchain setup, over-the-air updates, and the build pipeline. For the 80 percent of app use cases where you do not need custom native modules, Expo cuts weeks off the project time.
The cases where we pick Flutter instead are narrow. Apps with heavy custom graphics or animations benefit from Flutter's rendering model. Teams that already have Dart expertise have a faster ramp. Neither of those is common in the mobile app work we usually do, so Flutter ends up being a minority of our stack.
The argument is not that cross-platform always wins. It is that for the typical business app, the performance cost is negligible and the maintenance savings are real. Picking React Native as the default and overriding to native only when the app genuinely needs it is the pragmatic answer, and it scales.