Skip to content
Bilal Aksoy
7 min read

The cost that did not disappear

Shopify moved its mobile apps back to native and named coding agents as the reason. I went looking for what that argument means for a team that is not Shopify.

On September 10, Shopify published a post saying it is moving its mobile apps off React Native and back to Swift and Kotlin. Six years earlier the same engineering blog had argued the opposite, under a headline with the same shape.

2020

React Native is the Future of Mobile at Shopify

shopify.engineering
2026

Native is now the future of mobile at Shopify

shopify.engineering
Shopify Engineering, six years apart

A day later Ji Pei posted a clip of Notion's mobile app being rebuilt natively. Two announcements inside a week, and the reading that spread was that cross-platform is finished and coding agents are what finished it.

I had a direct interest in whether that was true. I build a white-label school lunch ordering platform: parents order meals for their children, the kitchen sees what to prepare, and the payments run through it. Three of us put the first version in production in three weeks. It is one Dart workspace with Serverpod on the server and Flutter on every client, and today it ships a parent app to iOS, Android and the web, a console for the people running the kitchen, and an internal admin console. If the argument going around holds, I should be costing out a migration. So I read both posts instead of the summaries.

What Shopify actually said#

Coding models got good enough to implement a feature in one language using the other implementation as the reference, which removes most of what made two codebases expensive in 2020. Native keeps them closer to platform APIs, with fewer framework layers in the way. The Shop app went from proof of concept to a rebuilt native app in the stores in twelve weeks. They are still sponsoring React Native Skia through the end of the year and still patching FlashList, which is not how a company behaves when it thinks a technology failed.

The sentence most of the commentary walked past is in the same post:

native still means building and maintaining software on two platforms, that cost has not disappeared

Shopify wrote the counterargument down themselves. The cost did not go away, it got affordable at their size.

Twelve weeks is the number that got repeated. What produced the twelve weeks got repeated much less: they built Helix, an internal system that drives the migration screen by screen, cutting each one into pieces small enough for an agent to finish. A plan for two mobile codebases that starts with building an agent orchestration platform is a plan that assumes a company with a platform team in it already.

Notion is a different migration#

Notion did not leave React Native in 2026, because Notion left React Native years ago. Its mobile apps have had native Swift and Kotlin shells since around 2019, and the piece that stayed cross-platform was the editor, running in a webview. Apple confirmed the SwiftUI work at WWDC in June. Ji Pei is showing the end of a webview.

So the two announcements started from different places. One team is leaving a cross-platform framework. The other is finishing a webview migration it has been doing incrementally for most of a decade. Put together they look like a trend; taken apart they are two companies with large mobile teams deciding that the remaining gap in platform fidelity is worth paying to close.

The half of the bill agents did not touch#

The arithmetic did move, and it moved on one line item. Agents took over porting a screen from Swift to Kotlin, writing the second set of tests from the same spec, and holding two implementations of one feature in step. That was the expensive part in 2020 and it is much cheaper now.

They did not take over anything that happens after the code exists. Each platform keeps its own bug queue, its own release train and its own rollback plan. Each gets its own dependency upgrades and its own crop of regressions every September. A business rule lives in two places and can drift in either of them. A person still has to read all of it before it ships, at a point where agents have already made reading the constraint rather than writing.

There is a second thing an agent will not hand over. It will write me Swift; it will not tell me when the Swift is wrong. Shopify has a decade of iOS and Android experience in the building to catch what a model gets wrong about lifecycle or threading. Three Dart developers generating SwiftUI have produced code that nobody there can review.

Count the surfaces#

Every version of this argument assumes the choice is iOS against Android: two targets, one decision. That is not the shape of the product I described at the top, and I doubt it is the shape of most products.

How the choice gets argued
iOS
Android
What the product ships
Parent app iOS · Android · web Kitchen console web Admin console web One Dart core Models, validation and endpoint contracts

The compiler checks every surface against the same contract.

One core, every surface

The parent app is one Flutter codebase running on iOS, Android and the web, so going native does not add a codebase, it adds two and leaves the web one where it is. It would also cut those clients off from the contract the rest of the system runs on. A model, a validation rule and an endpoint signature are written once today, and the compiler checks them on every surface that touches them. Replace the Flutter clients with Swift and Kotlin and that guarantee turns into an API layer somebody writes and keeps correct by hand, once per platform.

The kitchen console makes the point from the other end. The people using it are on their feet during a lunch service, checking it on whatever phone is nearby. They open it in a browser. Nothing sits between a fix and the person who needs it: no store review, no release train, no copy in the wild that is three weeks behind. Web is a cross-platform decision too, and nobody spends a week arguing about that one.

What the second codebase buys#

Native buys real things. A new OS ships and the platform idioms are there that day instead of after a framework release. Gestures and scrolling behave correctly without anyone tuning them, widgets and background work and share sheets arrive without a plugin in between, and the binary is smaller and starts faster. The tax runs the other way too: on Flutter I wait for a framework release to reach an OS feature, and sooner or later I own a plugin whose maintainer moved on.

Whether that is worth a second codebase turns on one question more than on any framework comparison. Is the app the product, or a client of the product? Shop is Shopify's product. How the editor feels is most of what Notion sells on a phone. A console for a school kitchen is a client of something else, and the fidelity gap costs it nothing.

What I decided#

Shopify's migration is evidence for the opposite of what it keeps getting cited for. They ran React Native for six years, learned what their product was, and paid to move once the numbers changed: twelve weeks, with a system they built for the purpose.

That is the normal shape of a system that lasts. You take on a limitation you can see, you ship, and you pay it down once the product has told you enough to make the payment worth making. OpenAI put the same idea in writing the same week, calling the Python service they already knew they would outgrow a strategic incursion of technical debt. Shopify did it with React Native and never gave it a name.

Being replaced later is not what makes a choice wrong. React Native carried Shopify for six years, and the tooling that now makes leaving it affordable is the same tooling being cited as the reason nobody should have picked it.

Two mature native codebases folded back into one is the migration nobody writes a post about. I am staying on one codebase until I know enough about this product to say what the second one would be for.