The Flutter vs React Native debate used to be about ergonomics and ecosystem. In 2026 it is about something more interesting. Both frameworks finished long-running architectural rewrites — Flutter migrated to Impeller everywhere, React Native finished rolling out the New Architecture (Fabric, TurboModules, JSI) as the default. The benchmarks that were true in 2022 are not true now. The mental models that engineers carry from a 2023 trial are out of date.
I have shipped one app on Flutter and one on React Native in the past twelve months, both with non-trivial native integration. This post is the version of the comparison I wish I had read in January. It covers how each stack actually renders in 2026, how each one talks to native code and hardware, where the performance lives, and which one I would pick for which kind of project. No "it depends" without a specific answer.
Context: what changed under the hood
If your last serious comparison was before 2024, the most important thing to know is that both stacks replaced their rendering and bridge layers. They are not the same products they were.
React Native New Architecture became the default in version 0.76 (October 2024) and has been the only supported path for new apps for a year. The old asynchronous bridge with JSON serialization is gone. In its place:
- JSI (JavaScript Interface) — a thin C++ layer that lets the JS engine hold direct references to host (native) objects. No serialization, synchronous calls possible.
- Fabric — the new renderer. The shadow tree lives in C++ and is shared between threads. View flattening and concurrent rendering work properly. Layout still uses Yoga.
- TurboModules — native modules are lazy-loaded and described by Codegen-generated specs, giving type safety on both sides.
- Bridgeless mode — the legacy bridge object is removed entirely. Startup is faster and the failure modes are clearer.
- Hermes — the default JS engine, AOT-compilable, with direct JSI integration.
Flutter finished its Impeller migration. As of Flutter 3.27 Impeller is the default renderer on Android (it had already been the default on iOS since Flutter 3.10), with the Skia backend kept as a fallback. Impeller compiles shaders ahead of time, eliminating the jank that the Skia backend produced when shaders were compiled on first use during scrolling or animation. Other 2024-2025 changes worth knowing:
- Dart 3.x with records, patterns, sealed classes, and sound null safety as the only mode.
- dart:ffi matured for direct C interop without the cost of a platform channel.
- Pigeon is the standard way to define typed platform channels.
- Add-to-app improved enough that gradual Flutter adoption inside a native shell is a viable path.
The headline: both stacks now have a proper synchronous-capable native bridge and a renderer that does not stall on first frame. The architectural gap between them is smaller than ever, and the differences that remain are deeper.
How each one renders, in 2026
This is where the honest mental model lives.
Flutter owns the entire pixel pipeline. Your widget tree is reconciled in Dart, lowered to a render tree of RenderObjects, painted into a layer tree, and handed to Impeller. Impeller turns it into Metal command buffers on iOS and Vulkan command buffers on Android (with an OpenGL ES fallback on older devices). The OS's native widgets — UIView, android.view.View — are not in the tree. There is one FlutterView host on each platform, and Flutter draws everything inside it.
React Native in 2026 still uses native views. A <View> is a UIView on iOS and an android.view.View on Android. The new piece is Fabric: when your component tree changes, the diff is computed in C++ on a background thread, and the resulting mutations to the native view hierarchy are applied on the main thread. Layout is computed by Yoga in C++. The JS engine (Hermes) drives the React reconciler and calls into Fabric via JSI.
The consequences:
- Pixel parity: Flutter is identical across iOS and Android because Flutter draws everything. React Native renders with the host platform's actual widgets, so a
<TextInput>is aUITextFieldon iOS and behaves exactly like one. - Custom rendering: Flutter's custom paint, complex animations, and Skia-style effects are easier and faster. React Native needs to back custom drawing onto a native canvas (Skia via
react-native-skia, or platform-specific code). - Accessibility: React Native inherits the platform's a11y tree for free. Flutter must populate the semantics tree explicitly; the framework does most of this for stock widgets but custom widgets are on you.
- Platform feel: React Native's
<TextInput>magnifier, scroll deceleration, and selection toolbar are exactly the platform's. Flutter's are reproductions, with the gaps documented in Flutter on iOS still does not feel native.
Architecture, side by side
Caption: Flutter renders to its own surface; React Native composes the platform's actual view hierarchy. Both have direct, type-safe paths to native code in 2026, but they reach the screen via different pipelines.
Talking to native code and hardware
This is the area where the New Architecture closed the largest gap.
React Native: JSI + TurboModules + Codegen
The legacy bridge serialized arguments to JSON and posted them across an asynchronous queue. In 2026 you do this instead:
Codegen generates the Objective-C++ and Java/Kotlin protocols. Your Swift implementation conforms to the generated protocol. The JS call goes through JSI, which holds a direct reference to the native object. Synchronous calls are possible (and now reasonable), though async is still the default for anything that does I/O.
Flutter: MethodChannel, Pigeon, FFI
Platform channels are still asynchronous and message-based. The 2026 best practice is Pigeon:
Pigeon generates type-safe Swift and Kotlin sides. Async by default, with the same threading discipline as a hand-rolled channel. Details in Writing a Flutter platform channel in Swift.
For high-frequency, low-latency native calls, Flutter has dart:ffi. You can call into a C ABI directly with no channel round-trip:
This is the closest you can get to "native call from a high-level language." React Native does not have a true equivalent; you would build a TurboModule that wraps the C function and call it via JSI, which is fast but adds a layer.
The synchronous question, honestly
Both stacks can now make synchronous-style calls into native:
- React Native's JSI lets a TurboModule expose a synchronous method that the JS thread calls directly.
- Flutter's FFI lets Dart call native C functions synchronously.
Whether you should is a different question. Synchronous calls block the calling thread. On the UI thread, that means dropped frames. The right pattern in both stacks is still: keep the call asynchronous unless you have measured a reason for synchronous.
Performance, with numbers that matter
The honest 2026 picture, from real apps not synthetic benchmarks:
- Startup time: Flutter cold-starts faster on iOS by a small margin (the engine is preloaded with the app binary). React Native with Hermes precompiled bytecode and bridgeless mode is much closer than it was; the gap is now ~50–150ms on a recent device, not seconds.
- Scroll performance: both hit 60 fps comfortably, both can hit 120 fps on ProMotion / high-refresh devices for typical content. Flutter's
Sliverfamily is excellent. React Native'sFlashList(from Shopify) is what to use; the standardFlatListis acceptable but not as good for very long lists. - Animation: Flutter's animation primitives are still better, especially for synchronized multi-target animations. React Native's
react-native-reanimatedv3+ runs animations on the UI thread via worklets and closes most of the gap. - Custom drawing: Flutter wins easily. React Native needs
react-native-skia, which is excellent but adds a dependency. - Memory: roughly comparable. Flutter's binary is larger; React Native's JS engine + bytecode adds overhead. Neither is dramatically lighter than the other.
- Frame stability under load: Impeller eliminated the shader compilation jank that haunted Flutter on first run for years. Fabric's concurrent rendering eliminated the JS-thread-stall jank that haunted React Native. Both stacks are now stable under load; the framework is rarely the bottleneck.
Usage: how a real screen looks
A typical screen — list of items, tap for detail, pull to refresh — looks structurally similar in both stacks now.
The line count is similar. The mental model is similar. The big differences are not on this screen; they are on the screens that need custom drawing, complex gesture choreography, or platform-feel parity.
Pros and cons
Flutter
Pros:
- One pixel pipeline, identical UI across platforms.
- Excellent animation and custom-paint story.
- Impeller eliminated the historical first-frame shader jank.
- Dart's null safety and records make refactoring safe.
dart:ffiis the cleanest native interop in any cross-platform stack.- Strong tooling: DevTools, profiling, hot reload that works.
Cons:
- iOS feel parity is still a manual effort. See Flutter on iOS still does not feel native.
- Larger binary size out of the box. See Why our Flutter app was 200MB and how we got it down to 38MB.
- Hiring is harder than React Native in most markets.
- Web target works but is not the strong suit; do not pick Flutter for a web-first product.
- Accessibility requires deliberate work for custom widgets.
React Native
Pros:
- Native widgets mean platform feel for free, including text input and selection.
- Massive web-developer talent pool. Hiring is easy.
- Code sharing with a web app is realistic via React Native Web or shared business logic.
- New Architecture (Fabric + TurboModules + JSI) closed most historical performance gaps.
- Expo turned the build/release pipeline from a pain point into a strength.
- Reanimated v3 + Skia + Gesture Handler give you the same custom-rendering power Flutter has, with one extra dependency.
Cons:
- The version-upgrade story is still painful. The 0.x version stream means breaking changes are frequent.
- Native module ecosystem fragmentation: many packages have not migrated to TurboModules yet, even in 2026.
- Two languages to debug (JS + native) for any non-trivial issue.
- Memory and binary cost of bundling Hermes + JS bytecode + native modules.
- Bridgeless mode helped but JS-thread starvation under heavy work is still a class of bug, mitigated by
runOnUIworklets, not eliminated.
When to choose which
Choose Flutter if:
- Pixel-perfect identical UI across platforms is a product requirement (often true for branded consumer apps and games).
- The product needs heavy custom rendering, complex animation, or 2D graphics.
- The team has Dart appetite or is small enough that one mental model matters more than ecosystem breadth.
- You will use FFI for native libraries (audio, ML, signal processing).
- You are not building a web-first product.
Choose React Native if:
- Hiring from a web-developer pool is important.
- Platform feel parity matters and you do not want to reproduce it manually.
- You want to share business logic with a web app.
- You are using Expo and want the managed-workflow benefits.
- The product is content-heavy with stock UI components rather than custom drawing.
Choose neither and go native if:
- Your product is iOS-led and depends on the latest iOS-only features (Live Activities, App Intents, complex Widget timelines, CarPlay, watchOS). The cross-platform tax is high here.
- The product is a system app, a launcher, or anything deeply integrated with platform services.
- See Should your team rewrite the native app in Flutter? for the full version of this argument.
A simple decision flow
Caption: a real decision flow. If two answers point at the same stack, that is your answer. If they split, the tiebreaker is hiring.
What I would do differently
- I would not have re-run a 2022 benchmark in 2025 and called it current. Both stacks moved enough that old numbers are misleading.
- I would have evaluated React Native with Fabric and Hermes from the start, not the legacy bridge that some tutorials still reference.
- I would have used Pigeon and Codegen on day one for both stacks. Hand-rolled native modules and channels age badly.
- I would have profiled real screens, not synthetic list-of-10000-rows tests. Both stacks pass synthetic tests; real apps are different.
- I would have written down the platform-specific work I would not avoid (widgets, watchOS, App Intents) before picking a stack. Cross-platform never escapes that work.
Closing opinion
In 2026, both Flutter and React Native are credible choices for serious apps. Pick Flutter if the UI is custom and identical-across-platforms is a product feature. Pick React Native if hiring or web-code-sharing is the bigger constraint and platform-feel parity matters. Stop comparing them on year-old benchmarks. The architectural rewrites on both sides are real, and the right answer for your team probably hinges on hiring and product surface area, not framework speed. For the broader Flutter-vs-native picture, see I have shipped apps in Swift, Kotlin, and Flutter. For where this fits with the GenAI features story, see GenAI features in a Flutter app.
Written by the author of Flutterstacks
A developer who shipped production apps in Swift, Kotlin, and Dart — with a genuine native reference point that most Flutter writers simply don't have.
More articles →