Start free Get a demo

The Great Unwind

When Frameworks Stop Making Sense

In a steam-powered factory, the layout followed the power supply. An engine turned an overhead shaft the length of the building, with belts carrying power down to the machines. The work had to fit around the machinery that powered it.

A circa-1890 machine shop with overhead shafts and belts descending to machines, surrounded by pulleys and large gears.
A machine shop, circa 1890. Wellcome Collection.

Early electrification kept much of that arrangement, with motors replacing steam engines but driving the same shafts. Giving each machine its own motor opened up a much bigger opportunity: the belts could come down, and factories could arrange the floor around the work instead of the power supply.

A layout that had seemed inevitable turned out to depend on a constraint that no longer applied.

Software is full of arrangements like that.

In 2020, Shopify bet on React Native: write a feature once, ship it on both platforms, spend less time chasing parity. It worked for six years. On September 10, 2026, Shopify announced its return to native.

Shopify’s agents could use an existing app as a reference to implement features in Swift and Kotlin, wire up data, and refine layouts from visual feedback. Engineers set direction and reviewed the results, but no longer had to write every platform’s implementation themselves. A core team of six, joined midway by feature teams, rebuilt the Shop app in twelve weeks.

The comparison below shows what users got back: faster launches on both platforms, a smaller Android download, and fewer sessions ending in a crash.

What users got back

50 %

less time to openAndroid cold start

109 MB

smaller appAndroid app size

10 ×

fewer crashes1Sessions that crash

Shop appReact NativeNativeChange
Android cold start4,433 ms2,233 ms−50%
Android app size293 MB184 MB−109 MB
Session stability99.5%+99.95%+10× fewer crashes¹
iOS cold start3,200 ms2,466 ms−23%
iOS app size67 MB68 MB+1 MB
¹ Shopify reports a tenfold reduction in sessions that crash.
Shopify Engineering, September 10, 2026. Two shipped releases, including product simplifications. Cold start runs from icon tap to visible home feed. These figures do not isolate framework overhead.

These releases also included product simplifications, so the gains cannot all be assigned to removing a framework. But an architectural choice defended mainly by you’d have to write it twice becomes harder to justify as agents reduce that extra work. Maintaining two apps can still cost more. For a large user base, though, faster launches and fewer crashes pay off across millions of sessions, potentially outweighing the remaining engineering overhead.

Shared code also helps keep one product coherent across two platforms, so teams don’t have to interpret every change separately. Security, correctness, interoperability, and domain knowledge remain worth sharing. If we separate the implementations, we still need a shared definition of how the product should behave.

What if we shared the behavioral contract instead of sharing the implementation?

The contract spells out the promises users rely on: a saved item survives a restart, a failed payment leaves the cart intact, and an offline save syncs when the connection returns. Those promises should hold regardless of which language, framework, or team sits behind the app.

In MirrorCode, a benchmark from Epoch AI and METR, models rebuild programs without source access. The best rebuilds of gotree, a command-line biology toolkit, passed 2,000 of 2,001 checks against the original.

The check that caught the difference

2,000 / 2,001

checks passed in a gotree rebuild

Date annotationgotree cut dateBoundary mismatch
Each square is one check One date-annotation mismatch
Best reported gotree result · Original source withheld from the agent
Independent research from Epoch AI / METR, not a result from Shopify’s migration. Selected best gotree result; pretraining contamination cannot be fully ruled out.

Each square above represents one check. The amber square marks the one test that failed: a date cutoff exactly matching an existing node’s date produced an extra root node. That single difference matters to anyone relying on the original behavior, and even a perfect score would only cover the inputs tested.

For a mobile migration, the previous app’s behavior is the contract, except where the team deliberately chooses to change it. You should be able to run the same journeys through both apps from equivalent account, data, and permission states. Visually compare screens, content, and interactions, then check persisted data, API effects, and analytics events. Review execution traces and performance profiles for errors, bottlenecks, and unnecessary work. The rewrite needs evidence that the product survived the change in code.

For a greenfield product, there’s no previous app to compare against, so you need to specify the expected screens, states, and transitions up front.

Keep those expectations under version control so an agent can use the visual evidence to fix a regression, rerun the same journey, and continue once the expected behavior is restored.

The same agents that make sweeping code changes possible can help verify them. The recording below shows a swarm exploring different paths through an app in parallel on cloud devices, returning visual evidence in live reports. Applied to both implementations, that exploration can help uncover differences for the team to investigate.

A swarm of agents explores different paths through a mobile app in Revyl, with live device screens beside a shared exploration activity report.
Agents exploring an app in parallel in Revyl. The screens and states they capture establish what a new implementation needs to preserve.

The captured screens become more useful when you can see how a user moves between them. In the Atlas recording below, screens form a map connected by the actions agents took. Teams and coding agents can query that shared reference to understand how the app behaves and what a replacement must preserve.

The app’s observed screens and transitions, connected in Atlas. View full size.

After the rewrite, each PR can make that reference more useful, showing what changed for the user, what still works, and which differences were intended. Atlas automatically connects the visual evidence to the relevant screens and journeys. Verified behavior becomes a durable asset, growing more valuable as the code around it gets easier to replace.

In the illustration below, evidence from successive PRs expands the map while staying attached to the same screen identities. The highlighted screen gains new evidence without becoming a new node each time.

Pull requests
Atlas
Nodes are screens. Edges are actions between states. New evidence stays linked to the same screen identity.

Native back navigation, permissions, and share sheets may still need to follow each platform’s conventions. A shared contract needs to allow for those differences and keep unexplored paths distinct from verified behavior.

Two implementations still need maintenance, and no single migration can establish that native is cheaper for every team. But a behavioral contract lets you change the stack without rediscovering the product, so a framework stays a choice you can revisit.

Electricity let factories arrange the floor around the work. As agents reduce the cost of building twice, software teams gain more freedom to choose an architecture around the user. Two implementations may still take more work today, but the bet is that agents keep shrinking that overhead while faster launches and fewer crashes keep paying users back.

Users never asked for a particular architecture. They asked for an app that opens quickly, remembers their work, and behaves the way they expect. The point of cheaper code is to stop charging them for the compromises we made to produce it.

That bill is refundable.