Back to blog

Craft / 6 min read

Native or cross-platform? The wrong question, and a better one

Source code and developer tools open on a dark screen

Ask a room of developers whether to build native or cross-platform and you’ll get an argument with the emotional register of a football rivalry. It’s a strange thing to be tribal about. Both routes have shipped software used by hundreds of millions of people, and both have produced apps that get deleted within a week.

The reason it never resolves is that it’s the wrong argument. After enough projects the question stops being which is better and starts being which set of problems do you want to own — and before even that, there’s a distinction most of these conversations get wrong before anyone has said anything useful.

Wrapped is not cross-platform

“Cross-platform” and “wrapped” get used interchangeably. They aren’t the same thing, and conflating them is how this conversation goes wrong in the first five minutes.

A wrapper puts your website inside a web view and ships it to a store. React Native, Flutter and Kotlin Multiplatform do something else: your interface is composed of real platform views, or drawn by a real graphics engine, with your logic running in a runtime beside it. The distance between a web view wrapper and React Native is far greater than the distance between React Native and native.

That matters commercially, not just technically. Apple’s review guidelines say an app “should include features, content, and UI that elevate it beyond a repackaged website”, and guideline 4.2.2 adds that apps “shouldn’t primarily be marketing materials, advertisements, web clippings, content aggregators, or a collection of links”. Thin wrappers meet that rule with some regularity. Serious cross-platform frameworks don’t — they’re building the same UI everyone else is.

So the real choice is rarely native versus wrapped. It’s native versus a proper cross-platform toolkit, and that’s a much closer contest.

The case for cross-platform is stronger than it used to be

A few years ago it was fair to say cross-platform bought speed and cost fidelity. Much less of that holds now.

React Native’s New Architecture — Fabric, Turbo Modules, no bridge — became the default in version 0.76, removing the asynchronous serialisation layer responsible for most of the framework’s historic reputation for jank. Kotlin Multiplatform has been stable for sharing logic since late 2023, and Compose Multiplatform reached stable on iOS in May 2025, so sharing the interface is now a supported choice rather than an adventure. Flutter’s Impeller renderer pre-compiles shaders, which dealt with the first-run stutter that used to give Flutter apps away.

The most useful public evidence we know of is Shopify’s, because they published five years of React Native with numbers attached rather than vibes: screen loads under 500ms at the 75th percentile, and better than 99.9% crash-free sessions. Their own summary is the line we keep returning to — native doesn’t automatically mean fast, and React Native doesn’t automatically mean slow.

The productivity argument is the strong one, and it gets underrated because it sounds like an excuse. Building a feature once rather than twice isn’t merely half the work. It’s half the specs, half the QA passes, half the bugs, and no slow drift into two apps that behave differently because two teams read the same ticket differently. Feature parity is a tax levied every sprint forever, and cross-platform simply never generates the bill.

Native doesn’t automatically mean fast. Cross-platform doesn’t automatically mean cheap. Both are decided by the team, not the toolkit.

The case for native is also better than its caricature

The argument against native is that you pay twice for a difference nobody notices. Sometimes that’s true. Here’s when it isn’t.

You inherit the platform’s behaviour instead of re-implementing it. Text selection, scroll-to-top on the status bar, the interruptible back gesture, keyboard avoidance insets, Dynamic Type propagation, what the screen reader announces when a view changes. Every one is achievable cross-platform — that’s exactly the trap. None of them is impossible, so each gets a ticket, and across two years the backlog fills with work a native project never generated.

Some things aren’t shareable at all. Shopify are candid about this in the same write-up: they still reach for native on hardware-intensive work like scanning and on-device AI, on memory-constrained surfaces like widgets and watch apps, and on background work such as offline transactions in their point-of-sale app. That list is a fair map of where the abstraction runs out.

Platform redesigns are a recurring bill. Apple shipped Liquid Glass with iOS 26 in September 2025, its broadest visual overhaul since iOS 7. A SwiftUI app gets a good share of that adaptation for free. Anything drawing its own controls chases the new look deliberately — and it will happen again, on both platforms.

Framework upgrades cost real time. Shopify are blunt that moving between React Native versions takes significant work and sometimes forces restructuring, and that debugging is flakier than the native tooling. They absorb it with dedicated rotating developers. If your plan doesn’t name somebody who owns that, you haven’t costed the framework — you’ve costed the demo.

The five questions we actually ask

Not “which is better”, because that has no answer. These do:

How much of this app is interface, and how unusual is it? A product that’s mostly forms, lists and detail screens shares beautifully. A product whose value is a bespoke interaction — a camera pipeline, a canvas, a live-instrument feel — shares badly.

Who maintains it in year two? Three web developers handed a Swift codebase and a Kotlin codebase is a liability with a bow on it. Equally, a cross-platform app with nobody who can read a native stack trace is one gnarly crash from being stuck.

How often is it opened, and how long will it live? Software used daily for years justifies more upfront investment. Software used monthly for a season rarely does.

Is there a deadline the answer has to respect? If the honest requirement is six weeks to find out whether anyone wants this, spending them on two codebases isn’t craftsmanship. It’s avoidance.

What’s the hardware story? Bluetooth, background location, heavy media, on-device inference — the more of these, the more native code you’ll write anyway, and at some point you’re maintaining a bridge as well as an app.

So: native or React Native?

Mixed, honestly. A shared core of models, validation, sync and business rules — the parts that benefit from being identical — with the interface written natively where the interface is the product, and shared where it isn’t. Most real apps contain both kinds of screen, and the pragmatic move is to stop pretending it’s one decision for the whole codebase.

The failure we see most often isn’t picking the wrong framework. It’s picking one for a reason nobody wrote down, so nobody revisits it when the reason expires.


We build both, which is the only reason we can afford to be neutral about it. Our mobile practice covers native iOS, native Android and React Native, along with the backends and sync underneath them, store release work, and taking over apps somebody else started. A studio that only builds one of those needs it to be the right answer every time.

If you’ve got a project sitting on this decision, tell us about it. You’ll get the reasoning above applied to your actual constraints rather than a pitch — and if that lands on six weeks of work instead of six months, we’d rather say so early.