NK

Search

Search pages, projects, posts, components, and icons

All articles
Mobile13 min read

Flutter vs React Native vs SwiftUI vs Kotlin: Which Should You Pick?

Four ways to build a mobile app, compared on what actually decides it, rendering model, team, platform fidelity, and what each one costs you later.

flutterreact-nativeswiftuikotlinmobile

Every mobile framework comparison collapses into a list of bullet points that could describe any of them: fast, modern, great developer experience, strong community. All four of these are good enough to ship a serious product, which means the bullet points cannot be what decides it.

What decides it is a small number of structural differences, who draws the pixels, what you can share, and who you can hire, and those differences point at different answers depending on the app and the team, not at a winner.

This is the comparison I actually run through when someone asks. It covers what each one is, the four questions that settle most decisions, and where each choice hurts a year in.

Glossary

Everything this post uses, defined before it is used. Skip it if the terms are already familiar, or come back when one of them trips you up.

The one sentence the rest of this post expands: these four differ mainly in who draws the pixels and how much code the two platforms can share, and those two facts decide almost everything else.

Terms

TermMeaning
FrameworkThe toolkit you build an app on top of, supplying the structure and the building blocks.
NativeBuilt with the tools the platform maker supplies, in the language they intend, with no layer in between.
Cross-platformOne codebase producing apps for more than one platform.
Rendering engineThe code that turns a description of a screen into actual pixels. Flutter ships its own.
Platform viewA real control supplied by the operating system, like an iOS UITextView.
Declarative UIDescribing what the screen should look like for the current data, and letting the framework work out the changes.
Platform fidelityHow closely the app matches the conventions and feel of the phone it runs on.
Design systemThe written-down set of visual decisions an app makes, plus the code that enforces them.
Business logicThe rules of the app itself, as opposed to how it is displayed. Sync, validation, pricing, permissions.
BridgeThe boundary work between a framework's own language and native code. Historically React Native's main cost.
Native moduleReact Native's way of exposing platform code to JavaScript.
Platform channelFlutter's asynchronous message pipe between Dart and Kotlin or Swift.
InteropTwo languages calling each other, here Kotlin and Swift.
Talent poolHow many developers you can realistically hire for a given stack.
Binary sizeHow large the installed app is. Flutter starts higher because it ships an engine.
Web viewA browser embedded inside an app, which is how wrapper frameworks render.

Abbreviations

ShortFull formIn plain words
UIUser InterfaceEverything the user sees and touches
OSOperating SystemiOS or Android, in this post
KMPKotlin MultiplatformKotlin's approach: share the logic, write each platform's UI natively
IMEInput Method EditorThe system that turns keystrokes into text, especially for scripts like Chinese and Japanese
FFIForeign Function InterfaceCalling C code directly from Dart, with no message passing in between
JSJavaScriptThe language React Native runs its logic in
JSIJavaScript InterfaceReact Native's newer, faster route between JavaScript and native code
APIApplication Programming InterfaceThe set of calls one piece of code offers to another
FAQFrequently Asked QuestionsThe question section near the end

What each one actually is

They are not four instances of the same thing, and half the confusion comes from treating them as if they were. The useful distinction is what happens when your code says "put a button here". Flutter paints one. React Native asks the phone for one. SwiftUI and Compose are the phone. Kotlin Multiplatform does not answer the question at all, because buttons are the part it leaves to you.

Flutter draws everything itself

Flutter ships its own rendering engine. A Button is not a UIButton, it is pixels Flutter paints. One Dart codebase targets iOS, Android, web, desktop, and embedded.

That buys pixel-identical output everywhere and complete design freedom, and it costs you platform behaviour: text selection, accessibility, and IME handling are Flutter's reimplementations rather than the OS's.

React Native uses the platform's own views

React Native runs your logic in JavaScript and maps components onto real native views, <Text> becomes a UITextView. You write React, and the platform draws.

That buys native feel and platform behaviour for free, and it costs you consistency: two platforms with really different components underneath, which you will meet the first time a list scrolls differently on each.

SwiftUI and Jetpack Compose are the native answers

SwiftUI (Apple) and Jetpack Compose (Android) are declarative UI frameworks for one platform each. Same mental model as the other two, describe the UI as a function of state, with no abstraction layer.

Pairing them means two codebases. Which is the honest framing of "native": not one better thing, but two of everything.

Going deeper: Kotlin Multiplatform shares logic, not UI

An app has two halves. There is what it knows and decides, and there is what it shows. The other three options here share the second half. This one deliberately shares the first and leaves the second alone.

KMP is the odd one out and the most misunderstood. It compiles Kotlin for both platforms so you can share business logic, networking, models, validation, persistence, while writing the UI natively in SwiftUI and Compose.

So it is not really a competitor to Flutter. It is a different bet. Flutter says share the UI too. KMP says the UI is exactly the part worth writing twice.

The four questions that settle it

Feature tables do not decide this. These questions do.

Should the app look like the platform, or like your brand?

This is the single most useful question, and it splits the field cleanly.

If the answer is platform, the app should feel like it came with the phone, follow every OS convention, adopt new system styling automatically, then React Native, SwiftUI, or Compose. Flutter can imitate the platform, and it will always be imitation, chasing changes rather than inheriting them.

If the answer is brand, a strong custom design system that should look identical on every device, then Flutter is the strongest option in this list. It does not fight you, because there is no platform styling to override, and your designer's mockup is achievable rather than approximate.

What does your team already know?

Uncomfortable, and usually decisive.

A React team will be productive in React Native within a week. A team of JavaScript developers will be slower in Flutter for a month while Dart and the widget model land.

An iOS team that knows Swift should think very hard before choosing anything else, their existing expertise is worth more than any framework advantage on this list.

And "we will hire for it" is a plan with a cost: Flutter and React Native both have deep talent pools, KMP's is much shallower, and dual native teams are roughly twice the hiring problem.

How much of the app is UI?

An app that is mostly screens over an API, a marketplace, a booking flow, a dashboard, is mostly UI, and sharing that UI is where the savings are. Flutter and React Native shine.

An app that is mostly logic, a sync engine, offline rules, encryption, a domain model, has its complexity below the UI. That is exactly the case KMP was designed for: share the hard part, write two thin UIs over it.

Going deeper: how deep do you need to reach into the platform?

Anything the phone itself owns rather than draws, the camera, notifications, the watch, has to be asked for. On a native stack you just call it. On the others something has to carry the request across a boundary, and the price of that crossing is what this question is really about.

Every framework can reach native code, but the cost differs. Flutter uses platform channels or FFI. React Native uses native modules or its newer JSI bridge. SwiftUI and Compose are already there.

If your app leans hard on new OS features, a watch app, widgets, a rewritten camera pipeline, App Intents, native gets those on day one, and everything else waits for a plugin or you write the bridge yourself.

The comparison, without the marketing

Read this table down a column to understand one option, or across a row to see where the four genuinely disagree. The rows are ordered roughly by how often they decide something, so the top half matters more than the bottom.

FlutterReact NativeSwiftUI + ComposeKotlin Multiplatform
LanguageDartTypeScriptSwift + KotlinKotlin (+ native UI)
RenderingOwn engine, draws every pixelReal platform viewsPlatform-nativePlatform-native
What is sharedUI and logicUI and logicNothingLogic only
Platform fidelityImitatedInheritedNativeNative
Design consistencyIdentical everywhereDiverges by platformDiverges by designDiverges by design
CodebasesOneOneTwoOne shared + two UIs
Hiring poolLargeVery largeLarge but splitSmall
New OS featuresWait for pluginWait for moduleImmediateImmediate
Binary size floorHighest (ships engine)ModerateLowestLowest
Best fitBrand-led UI, many targetsReact teams, platform feelOne platform, or fidelity above allLogic-heavy apps, native UI

Two rows deserve caveats, because they get quoted out of context.

Performance is not in this table, deliberately. All four are fast enough that your bottleneck will be images, list rendering, or an unindexed query long before it is the framework. Anyone choosing between these on benchmark numbers is optimising the wrong variable.

"Codebases: one" is doing quiet work. One codebase is not one platform, you still test on both, still hit platform-specific bugs, still maintain two store listings and two release processes. Cross-platform reduces the code, not the surface area.

Where each one hurts a year in

The interesting information is not what they are good at.

Flutter hurts on platform integration and polish at the edges. Text selection handles, scroll physics, IME behaviour with some keyboards, and any brand-new OS feature. Also binary size: you ship an engine.

React Native hurts on the boundary. Anything crossing between JS and native frequently, animation driven by JS state, heavy lists, image-heavy scrolling, is where the architecture shows. The New Architecture improves this materially, and it does not eliminate it.

SwiftUI + Compose hurts on duplication. Every feature is specified once, built twice, tested twice, and drifts. Bugs get fixed on one platform and not the other. This is a real, recurring tax rather than a one-off cost.

Kotlin Multiplatform hurts on ecosystem and tooling. Fewer libraries, thinner answers when you search an error, and the Swift interop is workable rather than pleasant. You are earlier on the maturity curve than the other three.

Key takeaways

  • They are not four of the same thing. Flutter draws its own pixels, React Native uses platform views, SwiftUI/Compose are native, KMP shares only logic.
  • "Platform-like or brand-like?" splits the field faster than any feature comparison.
  • Your team's existing skills usually outweigh every framework advantage listed here.
  • UI-heavy apps favour shared UI (Flutter, React Native). Logic-heavy apps favour shared logic (KMP).
  • Performance is not the deciding factor. All four are fast enough. Your bottleneck will be elsewhere.
  • One codebase is not one platform. You still test, ship, and debug on both.
  • Each hurts somewhere specific a year in, platform polish, the JS boundary, duplication, or ecosystem maturity.

FAQ

Is Flutter dying because of layoffs at Google?

The team shrank. The project did not stop. Releases continue, Impeller shipped, and adoption outside Google is broad. It is a fair thing to weigh in a five-year bet, and it is not the crisis the headlines implied.

Is React Native still slow?

The old bridge deserved its reputation. The New Architecture, JSI, Fabric, TurboModules, removes the serialised bridge for most work, and the gap to native is now small enough that it rarely decides anything. Judge it on its current architecture, not on 2018 blog posts.

Can I use Kotlin Multiplatform with Compose everywhere?

Compose Multiplatform does target iOS, which turns KMP into a shared-UI option much closer to Flutter. It is younger and less proven on iOS than the rest of this list. Promising, but not the same maturity.

What about Ionic, Capacitor, or web wrappers?

They are a legitimate choice for content-shaped apps where a web view is actually enough. For anything with heavy interaction, gestures, or animation, you will feel the ceiling early. That difference in ambition is why they are not in the table above.

Which one should a solo developer pick?

Whichever you can ship with. If you know React, React Native. If you want one codebase across mobile, web, and desktop, Flutter. If you only care about iPhone, SwiftUI and enjoy the simplicity of not abstracting anything.

Does choosing wrong doom the project?

Rarely. Products fail from unclear scope and slow iteration far more often than from framework choice. What a wrong choice costs you is speed, and a rewrite is usually cheaper than teams expect, provided your business logic was not tangled into the UI.

Conclusion

There is no winner here, which is unsatisfying and true. Flutter is the best answer for a brand-led UI across many targets. React Native is the best answer for a React team that wants platform feel. SwiftUI and Compose are the best answer when fidelity matters more than duplication. KMP is the best answer when the hard part of your app is not the UI at all.

Answer the four questions honestly, platform or brand, what the team knows, how much is UI, how deep you reach, and usually one option is clearly ahead. If two still tie, pick the one your team will enjoy more, and spend the saved deliberation on the product instead.

References

Official documentation for the topics covered here.

Read more

If Flutter is where you land, the follow-ups are How to Build Your First Flutter App to get moving, then How to Structure a Scalable Flutter Application before the codebase grows. For what "Flutter draws its own pixels" really means, see Flutter Is Not Just a UI Framework.