On this page
"Should we use Flutter or React Native?" is one of the first questions founders and CTOs ask us about a mobile project. It is a reasonable question with an unsatisfying honest answer: both are mature, both ship high-quality apps to millions of users, and for most products either would work. The choice matters less than the team, the design and the scope.
That said, "either would work" is not a decision, and the differences are real at the edges. This article explains how we actually choose for each client: the questions we ask, a decision table we use in scoping calls, where each framework is stronger in 2026, and the cases where we recommend going fully native instead.
Where both frameworks stand in 2026
Both frameworks have spent the last two years fixing their historical weak points.
React Native now runs the New Architecture by default (since 0.76): the JavaScript Interface (JSI) replaces the old asynchronous bridge, Fabric handles rendering and TurboModules load native modules lazily. Hermes is the default JavaScript engine. Expo has become the standard way to start and ship a React Native app, with Expo Router for file-based navigation, EAS Build for cloud builds and EAS Update for over-the-air JavaScript updates. The React Native team itself recommends starting new projects with a framework such as Expo.
Flutter renders every pixel itself with the Impeller engine, now the default on iOS and on modern Android devices, which has largely removed the shader compilation jank that affected early Flutter apps. Dart 3 brought sound null safety everywhere, records and pattern matching. Flutter's support for web and desktop has improved, though web is still best suited to app-like experiences rather than content sites.
The practical consequence is that the old arguments ("React Native is slow because of the bridge", "Flutter apps feel janky on first run") are mostly out of date. The remaining differences are about rendering model, team skills and ecosystem.
The decision table we use
We walk through these questions with every client. No single row decides it; we look at where the weight falls.
| Question | Leans React Native | Leans Flutter |
|---|---|---|
| Does your team already write TypeScript and React? | Yes, strongly | — |
| Do you have a React web app to share logic or people with? | Yes | — |
| Is a highly custom, brand-led UI with heavy animation central? | — | Yes |
| Must the app look and behave natively on each platform? | Yes (uses platform components) | Possible with extra work |
| Is pixel-identical UI across iOS and Android a requirement? | — | Yes |
| Do you need over-the-air updates for quick fixes? | Yes (EAS Update is mature) | Possible (Shorebird) |
| Will you hire locally, and how large is each talent pool? | Larger JS/TS pool in most markets | Smaller but growing, often strong specialists |
| Do you need web and desktop from the same codebase? | Web via React Native Web or a separate React app | Yes, if the web target is app-like |
| Heavy dependence on third-party native SDKs (payments, video, analytics)? | Slightly broader SDK coverage | Good coverage, check each SDK |
In our experience, the first two rows decide most projects. If a company already has React developers, React Native lets them contribute from week one and share validation, API clients and business logic with the web app. If there is no existing team and the product's value is in a distinctive interface, Flutter often gets there faster.
Performance: what actually differs
For the typical business app (forms, lists, feeds, maps, media, payments), users will not notice a performance difference between a well-built Flutter app and a well-built React Native app. Both hit 60 fps on mid-range devices when the code is sensible, and both struggle when it is not.
The differences that do show up:
- Rendering model. Flutter draws its own widgets, so complex custom animations and transitions behave the same on every device. React Native renders real platform views, which feel perfectly native but can make very custom, animation-heavy UIs more work. Reanimated and Skia (via React Native Skia) close much of that gap.
- Startup time and app size. A minimal Flutter release build is a few megabytes larger than an equivalent React Native one because it bundles its engine. For most apps this is irrelevant; for markets with low-end devices and expensive data, we measure it.
- Long lists. Both need care. In React Native we use FlashList for large feeds; in Flutter,
ListView.builderwith fixed item extents where possible. - Heavy computation. Neither framework is where you run heavy computation. In React Native, JavaScript runs on a single main JS thread, so we move CPU-bound work to native modules. In Flutter, Dart isolates handle background work well.
A pattern we follow in both: profile on a real mid-range Android device early, because that is where problems surface first. A three-year-old Android phone is a better test device than the latest iPhone.
Hiring and team continuity
This is the factor founders underweight most. The framework you choose determines who can maintain the app after the first version ships.
- React Native draws on the very large pool of React and TypeScript developers. A web developer can become productive on a React Native codebase in weeks, though they still need to learn mobile-specific concerns: navigation, app lifecycle, permissions, store release.
- Flutter developers are fewer, but people who choose Flutter tend to specialise in mobile. Dart is easy to learn for anyone who knows Java, Kotlin, C# or TypeScript.
For a client who plans to hand the app to an in-house team within a year, we ask who that team will be. A healthtech startup with two React developers on staff was an easy React Native decision. A consumer fitness startup with no engineers and a design-led brand went with Flutter, and later hired a Flutter developer through a specialist community without much difficulty.
Ecosystem and native access
Both frameworks let you call native code when a package does not exist.
In React Native with Expo, you write native modules with the Expo Modules API in Swift and Kotlin, and config plugins let you change native project settings without ejecting from Expo's managed workflow.
// A small Expo native module exposed to TypeScript
import { requireNativeModule } from "expo-modules-core";
type BatteryModule = { getLevelAsync(): Promise<number> };
export const Battery = requireNativeModule<BatteryModule>("Battery");
const level = await Battery.getLevelAsync();In Flutter, platform channels (or the Pigeon code generator for type-safe interfaces) connect Dart to Swift and Kotlin.
import 'package:flutter/services.dart';
const _channel = MethodChannel('com.example/battery');
Future<int> getBatteryLevel() async {
final level = await _channel.invokeMethod<int>('getBatteryLevel');
return level ?? -1;
}Before committing to either, we list every third-party SDK the product depends on (payment providers, identity verification, video calling, analytics, mapping) and check that each has a maintained package for the chosen framework, or that the native wrapper is small. This takes an hour and has changed our recommendation more than once. A logistics client depended on a regional payment provider whose SDK had an official React Native wrapper and no Flutter support; that settled it.
When we recommend going native
Cross-platform is the right default for most products, but not all. We recommend Swift and Kotlin (or native for one platform plus cross-platform later) when:
- The core experience is platform-specific hardware. Advanced AR, custom camera pipelines, low-latency audio, complex Bluetooth LE interactions or background location with strict battery requirements.
- The product lives in platform extensions. Home screen widgets, watch apps, App Clips, CarPlay and Android Auto. Both frameworks can host these, but the extensions themselves are written natively, so the cross-platform saving shrinks.
- You need day-one access to new OS features as Apple and Google release them.
- You already have strong native teams on both platforms. Rewriting their work in a new framework rarely pays off.
- App size and startup time are critical in markets with low-end devices, and measurement shows the framework overhead matters.
A middle path we use often: a cross-platform app for the main product, with specific screens or features implemented natively and exposed through a module.
Cost and timeline implications
For a typical MVP with 10–15 screens, authentication, an API backend, push notifications and store release, we see similar budgets for both frameworks, roughly 8–12 weeks. Building two native apps for the same scope typically costs 1.6–1.9 times as much, because UI, state and business logic are written twice, although backend and design work are shared.
| Approach | Relative build cost | Relative maintenance |
|---|---|---|
| React Native (Expo) | 1.0x | 1.0x |
| Flutter | 1.0x | 1.0x |
| Native iOS + native Android | 1.6–1.9x | 1.7–2.0x |
Maintenance matters as much as the initial build. Each year brings new iOS and Android versions, store policy changes and dependency updates. With one cross-platform codebase, that work happens once.
Summary checklist
When a client asks us to choose, we go through this list:
- Who will maintain the app in 12 months, and what do they already know?
- Is there an existing React web app whose code or people we can share?
- Is the UI distinctive and animation-heavy, or should it feel platform-native?
- Have we checked every required third-party SDK for the candidate framework?
- Does the product rely on hardware or platform extensions that push towards native?
- Do we need over-the-air updates, and which tooling supports them?
- Have we profiled a prototype on a mid-range Android device?
If the answers do not point clearly one way, we pick the framework the long-term team is most comfortable with. A good app in either framework beats an average app in the "right" one.



