There is no best mobile framework, only a best fit for your team and your constraints. For most business apps that need iOS and Android from one team, Flutter or React Native is the sensible default: Flutter when you want one consistent UI and strong offline behaviour, React Native when you already have React and TypeScript developers. Go native (Swift and Kotlin) when the device or platform is the product, pick Kotlin Multiplatform when you want native UI with shared logic, and use Ionic, Capacitor or a PWA when the app is mostly forms and content your web team can already build.
The rest of this post is the reasoning behind that paragraph, a comparison table, and the order in which we ask the questions when a founder or product owner asks us what to build with.
The five ways to build a mobile app today
Native. Two apps: Swift with SwiftUI for iOS, Kotlin with Jetpack Compose for Android. Each uses the platform's own tools and gets new operating system features first. You pay for it with two codebases and, usually, two sets of skills.
Flutter. One codebase in Dart. Flutter draws every pixel itself with its own rendering engine (Impeller on iOS and modern Android), so the app looks and behaves the same on both platforms. Details in Flutter: when to choose it.
React Native. One codebase in TypeScript or JavaScript, written with React. Your components become real native views. Since version 0.82 it runs only on the New Architecture, and the React Native team recommends starting through a framework, which in practice means Expo. See React Native: when to choose it.
Kotlin Multiplatform (KMP). Shared Kotlin code for business logic, networking and storage, with either native UI on each platform or shared UI through JetBrains' Compose Multiplatform, which has been stable on iOS since 1.8.0. See Kotlin Multiplatform: when to choose it.
Web technology: Ionic, Capacitor or a PWA. HTML, CSS and JavaScript, either wrapped in a native shell with Capacitor (optionally with Ionic's UI components) or installed from the browser as a progressive web app. See Ionic, Capacitor and PWAs: when web tech is enough.
How the options compare
| Approach | Language | How the UI is drawn | What is shared | Strongest fit | Main watch-out |
|---|---|---|---|---|---|
| Native | Swift, Kotlin | Platform UI toolkits (SwiftUI, Jetpack Compose) | Nothing between apps, except the backend | Device-heavy apps, platform features on day one, large consumer apps | Two codebases to build, test and keep in step |
| Flutter | Dart | Its own renderer draws every widget | UI and logic | Branded apps, field and offline apps, one small team | Dart skills; native look is imitated, not inherited |
| React Native | TypeScript / JavaScript | React components rendered as native views | UI and logic, sometimes code with a React web app | Teams already on React; content and commerce apps | Dependency upgrades need discipline |
| Kotlin Multiplatform | Kotlin (plus Swift for native iOS UI) | Native UI per platform, or Compose Multiplatform | Logic always; UI optionally | Android-first teams, existing native apps, complex domain logic | iOS developers must be on board; Swift export still Alpha |
| Ionic / Capacitor / PWA | HTML, CSS, JavaScript | Web view (Capacitor) or the browser (PWA) | Often the same code as your web app | Forms, content, internal tools, a web team | Heavy animation, background work and deep device access |
Two things the table does not show. First, every option here is used for serious production apps; the differences are in fit, not in whether it is "real". Second, the backend, the API and the data model usually take more effort than the choice of UI framework, and they do not change whichever you pick.
What actually decides the choice
We rarely decide on technical preference. These are the questions that settle it, roughly in order of weight.
- Who will maintain it. An app lives for years. A framework your team, or the team you can hire in your city, can maintain beats a slightly better one nobody around you knows.
- How much the device matters. Bluetooth peripherals, background location, camera pipelines, widgets, watch apps and payment hardware all push towards native, or at least towards writing native modules alongside a cross-platform app.
- Offline requirements. A field technician in a basement or on a rural site needs a local database, a sync queue and conflict rules. Every framework can do it; the work is in the architecture, covered in offline-first mobile apps and sync architecture.
- How native it must feel. A banking or consumer app judged against Apple's and Google's own apps benefits from native controls. An internal inspection app mostly needs to be fast and clear.
- What exists already. An existing native app, a React web app or a Kotlin backend each tilts the decision towards the tool that reuses it.
A decision sequence by situation
This is the order we walk through with clients. Stop at the first step that clearly applies.
- Is it mostly forms, lists and content, used by staff or known customers? If your web team can build it and the app does not need heavy background work, start with a PWA or a Capacitor-wrapped web app. It is the cheapest thing to maintain.
- Is the device itself the product? Hardware integration, advanced camera or audio, platform features such as widgets or wearables at launch: build native, Swift and Kotlin.
- Do you already have native apps? Keep them native. Add Kotlin Multiplatform for shared logic, or Flutter or React Native for new self-contained screens, rather than rewriting.
- Is your team strong in React and TypeScript, or do you share code with a React web app? Choose React Native with Expo.
- Is your team Android and Kotlin first? Choose Kotlin Multiplatform, with Compose Multiplatform if you are happy to share the UI too.
- Starting fresh with one small team, a branded UI and offline needs? Choose Flutter.
The sequence is deliberately blunt. Real projects mix answers, and a mixed answer usually points to a combination: a Flutter app with two native modules, or native apps sharing a KMP core.
What we pick for field apps and customer apps
Much of our mobile work is offline-first field apps for technicians, sales teams and warehouse staff, often talking to Odoo, plus customer-facing apps for ordering, bookings and account self-service.
For field apps with one team building both platforms, our default is Flutter: one UI that behaves identically on the mixed Android devices field teams tend to carry, good local databases, and predictable rendering. Where the client's developers are React people, React Native with Expo is an equally good answer. Mobile apps for Odoo field teams covers what those apps need from the ERP side.
For consumer apps where polish on iOS matters and the budget allows two teams, native is still the benchmark, described in native iOS and Android: when to go native. What moves the budget either way is explained in what drives mobile app cost and timeline, and the last mile is in releasing to the App Store and Google Play.
If you are weighing options for a specific app, write down who will maintain it, what it must do offline and which device features it needs, then read the post for your top two candidates. Or bring that list to us through mobile app development or contact, and we will talk it through.
Questions we get asked
Is Flutter or React Native better for a business app?
Neither is better in general. Flutter suits teams starting fresh who want one consistent, branded UI and strong offline behaviour, because it draws its own interface. React Native suits teams that already write React and TypeScript, or want to share code and people with a React web app. Both produce production-quality iOS and Android apps from one codebase.
When should I build separate native iOS and Android apps?
Build native when the device or platform is central to the product: deep hardware integration, advanced camera or audio, widgets and wearables, or new operating system features on release day. Native also makes sense for large consumer apps that can fund two specialised teams. For most internal and business apps, a cross-platform framework is enough.
Can a PWA replace a mobile app?
For many internal tools, forms and content apps, yes. A progressive web app installs from the browser, works offline with a service worker and needs no store review. It is weaker for background tasks, deep device access and some iOS behaviour. If you need store distribution with web code, Capacitor wraps the same web app as a native app.
What is Kotlin Multiplatform used for?
Kotlin Multiplatform shares Kotlin code, usually business logic, networking and local storage, between Android, iOS and other platforms, while each app can keep a native UI. With JetBrains' Compose Multiplatform, which is stable on iOS, you can share the UI as well. It suits Android-first teams and companies with existing native apps.
Does the framework choice affect offline support?
Less than people expect. Native, Flutter, React Native and Kotlin Multiplatform all have mature local databases and background sync options. The hard part is the sync design: what is stored on the device, how changes queue while offline, and how conflicts are resolved. Web apps can work offline too, with more limits on storage and background work.