Blog

React Native solved a problem nobody had. Use Flutter.

Mike MillerMike MillerSeptember 16, 2026
Flutter vs React Native cover

On September 10, 2026, Shopify published Native is now the future of mobile at Shopify. Six years after telling the industry that React Native was the future, they're moving back to Swift and Kotlin. The Shop app already shipped: proof of concept to app stores in 12 weeks.

Half the internet read that as "cross-platform is dead." That's the wrong read.

Shopify didn't reject cross-platform. They rejected the specific bargain React Native offered, and the reason they could is that coding agents got good enough to make that bargain unnecessary. Here's the part nobody's saying out loud: the argument that killed React Native at Shopify doesn't apply to Flutter at all. Different bargain, different premise, different failure mode.

If you're starting a mobile app this quarter, build it in Flutter.

Your mom never cared about native components

React Native's founding promise was that your JavaScript would map to real native components. Your <Text> becomes a UILabel. Your <View> becomes an Android ViewGroup. The pitch was authenticity: it's really native, so it really feels native.

Your mom has never once cared whether that button was a UIButton.

Nobody has. Users don't inspect the view hierarchy. They notice whether scrolling sticks, whether the keyboard covers the input, whether the animation stutters when the list reloads, whether the thing looks like it was designed by someone who cared. Those are rendering and engineering problems. None of them are solved by inheriting the platform's widget for a button.

So React Native took on an enormous constraint to buy a benefit that only ever existed in an argument. Every screen you build is a negotiation with two foreign component systems. Your ceiling is whatever UIKit and the Android view system will let you do, minus the parts the bridge doesn't expose, plus the union of both platforms' layout quirks. When something breaks three layers down, you're debugging JavaScript, the bridge, and a native view you didn't write.

The New Architecture fixed a lot of that. Expo made the tooling genuinely good. Meta has been a serious steward. React Native in 2026 is a much better version of itself than it was in 2020. It's still a better version of a premise that was never worth defending.

Flutter is a render engine that happens to ship a framework

Flutter made the opposite call, on purpose, and took the heat for it for years.

Flutter doesn't use native components. It ships a rendering engine, currently Impeller, draws every pixel itself, and treats the screen as a canvas it fully owns. Buttons, text, shadows, transitions, the whole surface is Flutter's, on every platform, including ones that didn't exist when your app shipped.

Everyone treated that as the compromise. It's the entire advantage.

When you own the pixels, there's no negotiation. The widget renders the same on a five-year-old Android and a new iPhone because the same engine drew it. Your custom transition isn't fighting a platform animation system, it's yours. You want a scroll physics curve nobody has, a shader on a card, a layout that ignores every platform convention because your product isn't a settings screen? You do it.

That's closer to working in a game engine than working in a framework. Game engines never apologized for drawing their own UI, because nobody ever shipped a game and got told the menu didn't feel native.

Think that's Flutter-fanboy reasoning? Check who else placed the bet. JetBrains shipped Compose Multiplatform for iOS as stable, and it renders through Skiko, a Kotlin wrapper over Skia. Own pixels. No UIKit mapping. Different company, different language, zero stake in Flutter, same conclusion: if you want control of the experience, you stop asking the platform for permission.

The tradeoff is real and I'm not hiding it. Owning the pixels means you own accessibility integration, text input edge cases, and platform look-and-feel when you actually want it. You pay in app size. You wait on the framework or a plugin for brand-new OS surfaces. But you trade an unbounded ceiling problem for a bounded list of known costs, and I'll take that trade every time.

What Shopify actually proved

Read what they wrote, not the headline.

Shopify, on why the decision changed:

LLMs changed one of the core assumptions behind our 2020 decision,
so we reevaluated our mobile stack from first principles.

The 2020 assumption was: building a feature twice costs roughly twice as much. Agents broke that. Shopify's Shop app migration post is explicit that agents were most effective when they had an existing implementation to work from, which is precisely the two-codebase parity problem: build it on iOS, point the agent at it, get the Android version.

So the thing agents devalued is write once, run twice. That was React Native's entire reason to exist. It was a cost-avoidance play from day one, and cost avoidance is the thing agents are best at eroding.

Flutter's reason to exist was never cost avoidance. It was control of the canvas. Agents don't make control of the canvas cheaper, because there's nothing to duplicate. No amount of model improvement hands you a rendering pipeline you own.

That's why Shopify's post is a much bigger problem for React Native than for Flutter, and why "cross-platform is dead" is a lazy summary of it.

The hidden cost is review, not typing

Here's the part that got lost in the victory lap.

Shopify didn't go native by telling everyone to run more agents. One engineer proved feasibility in a week. A core team of six built the native foundations. Then they built a factory around it.

A migration workflow that ran subagents for source review, behavioral documentation, per-platform planning, implementation, and parity validation. A debugging tool that gave agents structured access to live app events, logs, and state. Multiple agent sessions across separate worktrees. A hard rule that iOS and Android stay at feature parity at all times.

That's a company building an internal platform to make two codebases safe. Shopify can build that. Your eleven-person team cannot, and more importantly should not want to.

Because agents didn't make code cheap. Agents made writing code cheap. Reviewing it is still on you, and review is the actual bottleneck. Two codebases means two diffs, two sets of tests, two regression surfaces, and two chances for the agent to silently drift the platforms apart while both PRs look fine in isolation. Shopify solved that with a parity mandate and custom validation tooling, which is another way of saying it's a real problem that costs real money.

One codebase is one verification surface. You're reviewing ten times the code you used to write. That math got better for Flutter in the last two years, not worse.

The differentiator is the experience

Now the part that actually decides this.

If an agent can generate a competent CRUD app in an afternoon, then a competent CRUD app is worth roughly what it costs to generate. The code isn't the moat. It stopped being the moat about eighteen months ago.

What's left is design and experience. How it feels in the hand. Whether the motion is yours. Whether someone screenshots a screen and you can tell it's your app with the logo cropped out.

Native components are, by definition, the components everyone else has. They're the platform's defaults, and defaults are where products go to look like each other. Flutter hands you a canvas instead. The ceiling on craft is your team, not your framework, and right now craft is the only part of software that hasn't been commoditized.

You can build a beautiful native app. SwiftUI and Jetpack Compose are both good. You'll build it twice, keep it in sync forever, and spend your design budget on parity instead of on the thing that makes people care.

When you shouldn't use Flutter

I'm not going to pretend this is universal.

Build it native if your app is basic. If it's lists, forms, auth, and a settings screen over your API, native is the correct answer today. SwiftUI plus Compose plus an agent is a genuinely good workflow for that shape of app, and you get day-zero OS features for free.

Build it native if the OS is your product. Deep widgets, Live Activities, watch and TV surfaces, aggressive background work, new on-device model APIs the week they ship. Wrapping that through a plugin layer is a tax on the thing you're actually selling.

Stay on React Native if you're already there and it's working. Migrations are how good quarters die. Expo is good, the New Architecture is default, and Meta is still investing. Shopify's math was Shopify's math, and they said so.

Think hard about Dart hiring. It's a smaller pool than JavaScript. It's also a pool that's easier to onboard into than most people expect, and agents write Dart fine.

What I'd push back on is starting a new app on React Native in 2026. The framework is fine. The reason it existed isn't anymore.

The three-year clock

Here's my number.

Agents today are good enough to keep two native codebases in sync if you build a platform around them. They're not good enough to make that free, which is why Shopify needed six engineers and custom tooling to do it in twelve weeks with an existing app as the reference. Give it three years and I think that gets close enough to free that greenfield native becomes the default for most teams, and the cross-platform argument narrows to teams that specifically want to own their rendering.

Which means Flutter's lead lasts exactly as long as the canvas advantage outruns the parity advantage. Google's 2026 Flutter and Dart roadmap reads like they know it: finishing the Impeller migration on Android by dropping the legacy Skia backend on Android 10 and up, WebAssembly becoming the default for web, and MCP servers for Dart tooling with support in Gemini CLI and Antigravity.

That last one matters more than it looks. Agent legibility is now a framework feature. The framework that's easiest for an agent to reason about, iterate on, and verify in one place has a compounding advantage over the framework that requires a parity harness. Flutter starts that race with one codebase and one render pipeline. Two native codebases start it owing a parity harness, which is the bill Shopify paid in engineers and custom tooling.

So: Flutter for now. Native for basic apps. Native for everything in three years, maybe. React Native's argument is the one that already ended.

Frequently asked questions

Is React Native dead after Shopify's move?

No. Meta still ships it, Expo is still improving it, and it still runs in production at Meta and Microsoft, and at Shopify itself during the transition. What changed is its main selling point. React Native existed to avoid building a feature twice, and agents made building it twice much cheaper. That's an argument problem, not a shutdown notice.

Why didn't Shopify move to Flutter instead of native?

They didn't evaluate Flutter publicly. Their post frames the decision as a first-principles re-run of their 2020 choice once agents changed the cost of two codebases, and native won for their team, their apps, and their existing React Native implementation to reference. A team optimizing for a single owned rendering surface instead of platform parity would run that math differently.

Does Flutter still make sense if agents can write native code?

Yes, for the apps where rendering control is the point. Agents lower the cost of producing code, not the cost of reviewing it, and two native codebases mean two review surfaces plus a parity problem to police. Flutter keeps that at one. Agents also don't give you an owned render pipeline, which is what Flutter is actually selling.

What about app size and startup time with Flutter?

Flutter apps carry the engine, so they start larger than an equivalent native binary. For most consumer apps that difference stopped being a deciding factor years ago, but if you're shipping into markets with hard download limits or you need the absolute fastest cold start, measure it before you commit.

Should I migrate my existing React Native app to Flutter?

Probably not on the strength of a blog post. Migrations cost quarters and buy nothing your users can see on day one. This argument is about what you start next, not what you tear down.