Native development means two separate apps: Kotlin with Jetpack Compose for Android and Swift with SwiftUI for iOS, with full access to every platform API. React Native (usually together with Expo) lets you write one app in TypeScript using the React model, while the screen shows real native components. Flutter also gives you one codebase, but in Dart, and draws the UI with its own engine; the choice between them depends on the device APIs you need, your team and how much platform code you are willing to maintain.
After this you will be able to
- Compare Kotlin/Compose, Swift/SwiftUI, React Native with Expo and Flutter by language, how the UI is rendered, device API access and shared code
- Explain why React Native is not “a website in a wrapper” and how its
ViewandTextcomponents differ from<div>and<p> - Walk through the decision tree and justify a stack choice for given requirements and a team
- List the build and publishing steps shared by all stacks, including iOS builds and storing signing keys
Contents
- First: do you need an app-store app at all
- Native: Kotlin with Compose and Swift with SwiftUI
- React Native and Expo: the React model and native components
- Flutter and Dart: its own rendering engine
- Comparison by engineering criteria
- Builds and publishing: what every stack shares
- How to choose: a decision tree
First: do you need an app-store app at all
Before comparing frameworks, check whether you need an installable app at all. MDN defines a PWA (progressive web app) as an app built with web technologies that runs on many platforms from a single codebase, can be installed on the device, works offline and integrates with the system. If your scenario fits within what the browser can do, a PWA is simpler to ship and update. We covered the business side of this choice — store review, acquisition channels, phasing — in “PWA or mobile app”; here is the engineering angle: what actually changes in code, tooling and team.
Engineering signs that the web will not be enough: the app has to live in the App Store and Google Play; you need APIs the browser does not expose, or exposes with limits on a particular platform; background work matters, as does tight system integration (widgets, sharing, biometrics, platform payments); you need a smooth, complex interface with gestures and animation on low-end devices.
Native: Kotlin with Compose and Swift with SwiftUI
A native app is written in the platform’s main language with the platform’s own tools. For Android that is Kotlin: since 2019 Google has developed the platform Kotlin-first and recommends starting new apps with it, while keeping Java support. The UI is built with Jetpack Compose, which the Android documentation calls the recommended modern toolkit for native UI: you describe the interface, and Compose updates it when the state changes. The IDE is Android Studio.
For iOS it is Swift and SwiftUI — Apple’s declarative framework for all of its platforms, with live previews in Xcode. SwiftUI can be adopted incrementally next to the older UIKit. Xcode is Apple’s toolset for developing, testing and distributing apps, and it runs on a Mac.
Strengths
- New system APIs are available immediately, with no wait for framework wrappers
- UI and behaviour match the platform exactly
- Official documentation, samples and profiling tools come from the OS vendor
Cost
- Two apps, two languages, two codebases — every feature is built twice
- You need developers for each platform, or people who know both
- Keeping behaviour and releases of two versions in sync is extra work
A middle ground is Kotlin Multiplatform. Google officially supports it for sharing business logic between Android and iOS, and JetBrains’ Compose Multiplatform lets you share the UI too if you want. It suits a team that already writes Kotlin and wants to stop duplicating logic without giving up native UI.
React Native and Expo: the React model and native components
React Native lets you write a mobile app in JavaScript or TypeScript using the same model as React: components, props, state, hooks. The fundamental difference from the web is that there is no DOM and no HTML. Instead of <div> and <p> you use the View and Text components, and at runtime React Native creates real Android and iOS views for them. It is not a website in a wrapper: the screen shows system UI elements.
View
- Android
ViewGroup- iOS
UIView- Closest web analogue
- non-scrolling
<div>
Text
- Android
TextView- iOS
UITextView- Closest web analogue
<p>
Image
- Android
ImageView- iOS
UIImageView- Closest web analogue
<img>
ScrollView
- Android
ScrollView- iOS
UIScrollView- Closest web analogue
- scrolling
<div>
TextInput
- Android
EditText- iOS
UITextField- Closest web analogue
<input type="text">
Since version 0.76, React Native enables the New Architecture by default: the asynchronous “bridge” between JavaScript and native code is replaced by JSI (JavaScript Interface) — direct calls without serialising data. It also supports the concurrent features of React 18 and later. The documentation is upfront that the New Architecture alone does not guarantee a speed-up: the gain depends on your app’s code.
The React Native team itself recommends starting new apps with a framework, and names Expo first: it provides file-based routing, a standard library of native modules and plugins that change native code without hand-editing the Android and iOS projects. At the time of checking, the current release is Expo SDK 57, built on React Native 0.86 and React 19.2.
Flutter and Dart: its own rendering engine
Flutter solves the same “one codebase, two platforms” problem differently. Instead of system UI elements it draws everything itself: Flutter has its own Dart implementation of every control, including counterparts of the iOS and Android switches. Rendering is done by a C++ engine with the Impeller renderer, which ships with the app; on iOS Impeller is the only supported renderer, and on Android it is enabled by default from API 29.
The code is written in Dart. During development the app runs in a virtual machine with hot reload — changes appear without a full rebuild and without losing state. For release, Flutter compiles the code directly to machine instructions. Flutter reaches platform APIs through platform channels — a message channel between Dart and native code — or through FFI for C libraries.
Comparison by engineering criteria
Language
- Native (Kotlin / Swift)
- Kotlin and Swift — two languages
- React Native + Expo
- TypeScript / JavaScript
- Flutter
- Dart
How the UI appears
- Native (Kotlin / Swift)
- System frameworks: Compose, SwiftUI
- React Native + Expo
- React components → native platform views
- Flutter
- Its own widgets, drawn by the Impeller engine
Shared Android/iOS code
- Native (Kotlin / Swift)
- None (or logic via Kotlin Multiplatform)
- React Native + Expo
- Most of the app
- Flutter
- Most of the app
New system APIs
- Native (Kotlin / Swift)
- As soon as the SDK ships
- React Native + Expo
- Via Expo and community modules or your own native module
- Flutter
- Via plugins or your own platform-channel code
Development loop
- Native (Kotlin / Swift)
- Build and previews in Android Studio / Xcode
- React Native + Expo
- Fast code refresh via Metro, Expo Go
- Flutter
- Hot reload in the Dart VM
Web from the same code
- Native (Kotlin / Swift)
- No
- React Native + Expo
- Yes, via React Native for Web in Expo
- Flutter
- Yes, Flutter web
Who to hire
- Native (Kotlin / Swift)
- Android and iOS developers
- React Native + Expo
- React/TypeScript developers with mobile experience
- Flutter
- Flutter/Dart developers
Performance is deliberately not reduced to a single number in the table: all three approaches end up running compiled native engine code on the device, and bottlenecks usually lie in the specific app — long lists, heavy images, unnecessary re-renders. Compare a prototype of your heaviest screen on a real mid-range phone rather than generic benchmarks.
Builds and publishing: what every stack shares
However the app is written, the output is a package for Android and a package for iOS, signed with developer keys and reviewed by the stores. The differences between stacks are smaller here than they seem.
Developer accounts
Google Play Console and the Apple Developer Program are registered to the company that owns the product, not to the contractor.
iOS builds
The React Native documentation says it plainly: building projects with native code for iOS requires a Mac. Cloud services such as Expo’s EAS Build build the iOS version on their own macOS machines.
Signing
Android signing keys and iOS certificates are critical secrets: lose them once and the trouble lasts. EAS Build can store and issue them for you; with a native build the team is responsible.
Store review
App Store and Google Play requirements are the same for every stack: a framework does not get around them.
Updates
Users get new versions through the store. For JavaScript code, Expo offers updates without a rebuild (EAS Update) within the stores’ rules.
How to choose: a decision tree
Below is the order of questions we use as a starting point. It is not a rule but a way not to miss what matters: a “yes” to an early question usually outweighs all the later ones.
Is the browser enough?
If the scenario is a catalogue, booking or customer account and app stores are not required, start with a PWA or a responsive web app.
Does the product depend on one platform or deep integration with it?
iOS only, widgets, Apple Watch, CarPlay, complex camera or background Bluetooth work — native development removes the risk of waiting for wrappers.
Do you already have a web product and a React/TypeScript team?
React Native with Expo lets you reuse the language, approaches, types and part of the business logic, while Expo covers the typical native infrastructure.
Do you need an identical branded UI on every platform, and is the team ready for Dart?
Flutter gives full control over every pixel thanks to its own rendering.
Do you have a strong Android team writing Kotlin?
Consider Kotlin Multiplatform: shared logic, native UI on each platform.
- The device APIs the product cannot work without are listed and their support in the chosen stack is checked
- It is clear who will maintain the code in two years and how easy it is to find a replacement
- You have decided whether you need the web from the same codebase
- The heaviest screen has been prototyped on a real inexpensive phone
- You have decided where and by whom the iOS version is built and where the signing keys are kept
Next on the path: your first app with React Native and Expo — from create-expo-app to a styled screen, then navigation with Expo Router. For Flutter there is a separate lesson on Dart and widgets.
