Ask someone to compare React Native and Flutter and you usually get "React Native if your team knows React, Flutter if you want better performance." It's not wrong, exactly. It's just the version that ends the moment the interviewer asks why Flutter would be faster, or how you'd actually pick for a specific app.
"React Native vs Flutter, how do you choose for a new app?"
I've shipped apps with both. The thing that makes the comparison make sense is one architectural fork, and almost every trade-off is downstream of it.
The fork: who draws the pixels
Both let you write one codebase for iOS and Android. They get there in completely different ways.
React Native: the operating system draws it
Your JavaScript describes the UI. React Native passes that description across to the platform, and iOS and Android render their own real native components. A <Button> in React Native becomes an actual UIButton on iOS and an actual Button on Android. React Native is a coordinator, the OS is the renderer.
Flutter: Flutter draws it
Flutter ships its own rendering engine and paints every pixel itself. It does not use the platform's native widgets at all. A Flutter button is Flutter drawing something that looks like a button, onto a canvas it controls end to end. The OS just hands Flutter a window.
That's the whole root of it. One delegates rendering to the platform, the other replaces it.

What follows from that
Look and feel
React Native inherits platform behavior for free. Scroll physics, text selection, accessibility, the little things update when the OS updates, because they are the OS. The cost is that fighting the platform's defaults is painful, and an app can feel slightly "off" on one platform if you only tested the other.
Flutter looks and behaves identically on both platforms, because it's the same pixels either way. Great when brand consistency matters more than feeling perfectly native. The risk is the opposite one, it can feel subtly non-native everywhere unless you deliberately match each platform's conventions.
Performance and jank
React Native's classic bottleneck was the bridge between the JS thread and native. Heavy work, long lists, animations driven from JavaScript, could stutter because everything funneled through that one channel. The newer architecture (JSI and Fabric) mostly removes the bridge, but the mental model still holds: keep work off the JS thread, run animations on the native driver, virtualize long lists.
Flutter compiles Dart ahead of time to native ARM code and renders on its own thread with no bridge in the middle. Animations tend to be smooth by default. When Flutter janks, it's usually an expensive build() method running too often, or rebuilding a bigger part of the tree than necessary.
Team and language
React Native is JavaScript or TypeScript plus React. If you already have a React web team, the ramp is close to zero and you can share validation logic, types, and API clients with the web app.
Flutter is Dart -- a new language for most people, though a small and consistent one that's quick to pick up. But there's no code sharing with a JS web codebase, and hiring pulls from a smaller pool.
Expo, and when you leave it
Most React Native apps now start with Expo: a managed setup with over-the-air updates and no need to open Xcode or Android Studio for routine work. You move to a bare or prebuild workflow when you need a native module Expo doesn't already wrap. That's the honest answer to "when would you eject", when a required native capability isn't covered, not before.
The native bridge follow-up
"How does React Native call a native API like the camera from JavaScript?" It doesn't, directly. A native module written in Swift or Kotlin exposes methods that JS calls, historically over the async bridge, now via JSI as a more or less direct function binding. Flutter's equivalent is a platform channel: Dart sends a named message, platform code handles it and replies. Same idea, message passing between the portable layer and the native one.
Kotlin, briefly
If part of the app drops to fully native Android, that's Kotlin. Over Java it gives you null-safety enforced by the type checker, coroutines for async code instead of callback nesting, and a lot less boilerplate, while staying fully interoperable with existing Java. Worth knowing even in a cross-platform project, because the day you write a custom native module, this is the language you write the Android half in.
Quick recap
- The core difference: React Native renders with the platform's real native widgets, Flutter paints its own pixels with a bundled engine
- Native feel and free platform updates favor React Native; pixel-identical cross-platform consistency favors Flutter
- React Native perf work is mostly about keeping the JS thread free; Flutter perf work is mostly about cheap
build()methods - Language and team decide a lot: React Native reuses a React/TS team and its code, Flutter needs Dart and shares nothing with web
- Native access is native modules (RN) or platform channels (Flutter), and the native half is Kotlin on Android either way
The answer that lands isn't "Flutter is faster." It's "they draw the UI differently, here's what that costs you on each side, and here's which of those costs my project can afford."




Comments
No comments yet — be the first to share your thoughts.