How mobile development actually works in 2026 — native, cross-platform, and what I’d start with

Dmitri Voronov

Dmitri Voronov

September 18, 2026

How mobile development actually works in 2026 — native, cross-platform, and what I’d start with

I do not start a mobile app by asking which framework is winning on Twitter. I start by asking how many screens are the product, whether we need camera or background location in anger, and whether I have even one person who will live in Xcode or Android Studio after the demo. In 2026 the menu is the same nouns — Swift/Kotlin native, Flutter, React Native, Kotlin Multiplatform — and the default I pick has changed less than the marketing.

Here is how the work actually happens, and the default I would choose on Monday for a B2B app, a consumer camera-ish app, and a “we already have a React team” app.

What “mobile development” is in practice

It is not writing screens. It is store review, push permission nags, a deep link that breaks after a universal-link entitlement, a background upload that iOS killed, a Play pre-launch report that fails on a device you do not own, and a release train that cannot ship because certificates expired. The framework debate is the fun part. The job is the boring part plus a UI toolkit.

Agents made the fun part cheaper. I can scaffold a Flutter or RN screen in an afternoon. They did not make App Store review cheaper. They did not make a bad navigation graph cheaper. They generate plausible widgets that ignore Dynamic Type and the back gesture. I review mobile diffs for those the way I review backend diffs for migrations.

I also treat “one codebase” as a cost statement, not a virtue. One codebase with two store processes, two design languages, and a bridge is still two products. You saved a mapper. You did not save the release manager.

Native, when I still start there

I start native when the product is the device: camera pipelines, serious offline, widgets, Live Activities, a Watch sibling, background geofences that must not drain the battery in a way we cannot explain. SwiftUI and Jetpack Compose are good enough in 2026 that I do not miss UIKit for a new UI, with the usual asterisk about the one screen that still needs the old API.

I also start native when I have (or can hire) one iOS and one Android engineer, or one strong native who will own one store and a contractor on the other. Two specialists on a device-shaped product beat a cross-platform generalist who will fight the grain on both.

Kotlin Multiplatform is the native-shaped compromise I take seriously: share the domain and networking in Kotlin, keep UI native. I have seen it work for a team that was already Kotlin on Android and willing to learn the iOS glue. I have seen it fail when people expected “write once” and got “debug twice plus Gradle.” I would use KMP for shared models and a grimy sync engine. I would not use it to avoid hiring iOS.

Two phones on a desk beside Xcode and Android Studio windows

Flutter, React Native, and the honest defaults

Flutter is my default when the UI is custom, the brand wants identical pixels, and the team can live in Dart. It is excellent for a designed client that is not trying to be an iOS citizen first. Impeller and the current toolchain are fine. The tax is Dart hiring and the day you need a platform channel for a payment SDK that the plugin wraps badly. I budget that day. I do not pretend it will not come.

React Native (and Expo) is my default when the company already thinks in TypeScript and the app is a companion: lists, auth, a WebView for the gnarly admin, push, a few native modules. Expo has made the first month kinder. The tax is the bridge, the upgrade, and the screen that needs to feel native and does not. I have shipped Expo to production for a field-ops app. I have also frozen an upgrade for a quarter because a library lagged. That is the job.

I do not pick RN so we can “share with the web.” Sharing a design system token is real. Sharing screens is usually a lie that produces a worst-of-both navigation model. A tRPC or REST client shared as a package is enough sharing for me.

I do not pick a fourth option — Ionic, a PWA-only “app,” a Kotlin Multiplatform Compose UI experiment — unless the constraint is already that stack. A PWA is a website. Sometimes that is the product. I will not call it a mobile strategy to avoid store fees if the user expected an app.

The default I would choose

B2B workflow, existing TypeScript shop, modest device needs: Expo / React Native. Hire one mobile-shaped engineer who has shipped a store build, not four web engineers who will learn on the entitlements file.

Consumer product with a custom UI and a small dedicated mobile team: Flutter, or native if the camera is the product.

Android-first shop with a Kotlin backend and a real iOS need: Kotlin Multiplatform for domain, Compose and SwiftUI at the edges — only if we already have the Gradle patience.

Anything with serious background work, widgets, or a platform feature that is the differentiator: native. I will not fight Apple from a plugin.

A weekend demo: Expo or Flutter, throwaway. I will not let the demo choose the next two years unless the constraints still match after the first review rejection.

A release checklist and two store listing printouts on a table

How the work actually runs week to week

A release train, not a hope. Fastlane or EAS, a build that is not on someone’s laptop, a TestFlight / internal-track habit. Crashlytics or Sentry. A flag system — I like the same LaunchDarkly or a small Unleash we already run on the API. Forced-update policy written down, because you will need it once.

I keep a thin BFF if the mobile clients would otherwise over-fetch a desktop API. I do not make the BFF a second product. I make it the cacheable, mobile-shaped read model.

Offline is a product decision. “It works on the plane” means a local store — Room, SwiftData, Drift, Watermelon — and a sync you can explain. Fake offline is a spinner and a toast. I have shipped the toast. I do not call it offline in the pitch deck anymore.

I test on a mid-range Android and an older iPhone, not only on the flagship on my desk. The Play pre-launch report will find the rest if I look at it. I have ignored it. I have regretted it.

A mistake I still replay

We picked React Native for a consumer app whose only memorable feature was a custom camera shutter with hardware timing. The plugin was “almost” there. Almost cost us a quarter and a native rewrite of one screen that then fought the rest of the navigation. We should have started native or accepted a boring camera. The framework was not wrong. The product grain was. I write that sentence on the decision doc now before anyone opens a template repo.

The opposite mistake is native-for-pride on a three-screen field form. We did that too. Two store trains, two design bugs, one angry PM. Expo would have been kinder. Pride is not a constraint.

What I tell founders who want one team to do everything

A React team can own an Expo app if you buy them time for store work and one person who has been rejected by Apple. They cannot own a camera social product because you saved on a native hire. The framework will not write your permission copy or your background-mode essay in the review notes.

I would start with the smallest honest surface: one store first if the audience is skewed, or both stores with a cross-platform UI if the product is forms and lists. I would not start with KMP and a design system and a white-label story. That is a third-year architecture.

Mobile development in 2026 is still store trains, permissions, and a UI toolkit. Native when the device is the product. Expo when the company is TypeScript and the app is a companion. Flutter when pixels must match and Dart is acceptable. KMP when Kotlin is already the house and the share is domain, not a dream of one widget tree. I pick from that list. I do not pick from a keynote.

If you are choosing this week, write the three device features you cannot fake and the team you actually have. The intersection is the default. Everything else is a rewrite you will schedule after the first one-star review about a keyboard covering the submit button — a bug no architecture tweet will prevent, and every stack can ship if you do not test on a small phone.

I have shipped all four shapes. The failures were mismatches, not missing frameworks. Match the product to the grain. That is how mobile actually works. The rest is a comparison table I no longer print. If you need a one-liner for the board: we are buying a store process and a permission story, and we will pick the toolkit that fights that story least. Framework wars do not show up in the crash-free session rate. The mismatch does.

More articles for you