The method
One screen at a time, five gates each.
Asking an agent to convert a whole app produces a lot of code quickly, and nobody can maintain it. What works is small checkpoints, each proven against the running React Native app before the next one starts. On 10 September 2026 Shopify described the same shape and how it rebuilt its Shop app. The Pack follows that published method. Shopify has no connection to Nativestarter.
- 1
Assess
An agent inventories every screen, native module, Expo package and OTA dependency, and produces a migration map with an effort estimate per screen.
Before the next step
A human signs off the map and the order of checkpoints.
- 2
Spec
For the next screen, an agent reads the React Native source and writes a platform-neutral spec: layout, state, data, navigation, analytics events, edge cases.
Before the next step
The spec is reviewed against the running app, not the source.
- 3
Port
Agents implement the spec in SwiftUI and Jetpack Compose, each using the other platform as a reference once one side exists.
Before the next step
Unit tests for the screen's logic pass on both platforms.
- 4
Prove parity
Both apps are driven to the same state and captured. Screenshots, copy, events and behaviour are diffed against the React Native original.
Before the next step
Every parity row passes, or a mismatch is accepted in writing.
- 5
Adversarial review
Two reviewer agents, one for parity and one for architecture, read the diff, the spec and the parity report. Their only job is to find what is wrong.
Before the next step
Findings fixed or dismissed with a reason, then a human approves the checkpoint.
Parity is a report, not a feeling.
Both apps are driven to the same state and photographed, and the screenshots and analytics events are compared against the original. A screen above the gate fails the checkpoint. A screen close to it needs a written acceptance.
On Bluesky, one feed row came out two pixels short and pushed every row below it out of line. That is exactly what a human reviewer misses.
Bluesky port, iOS
Matched-pair round, 22 October 2026
| Screen | State | Pixels that differ | Result |
|---|---|---|---|
| Home feed | Seeded feed | 1.44% | Drift |
| Post thread | Seeded feed | 0.97% | Pass |
| Profile | Seeded feed | 1.13% | Drift |
| Post thread | Dark mode | 0.96% | Pass |
| Profile | Largest text size | 1.86% | Drift |
| Home feed | Empty account | 1.94% | Drift |
What the agents need to be useful
Logic that runs without a simulator
Agents change code in seconds, then wait minutes for a build. Business logic that runs headless from a command line turns that wait into milliseconds, so every checkpoint's tests are cheap enough to run every time.
A way to put the app in a state
Parity is only checkable if both apps can be driven to the same state on demand: signed in, a seeded feed, an empty account, the largest text size. One Maestro flow can drive the React Native app and both native apps.
A reviewer that disagrees
The agent that wrote a screen will approve it. The reviewer is a separate agent with one brief: find what is wrong with this diff, spec and parity report. A human approves after it, not instead of it.
Sometimes the right answer is to stay.
Worth migrating when
- Your iOS and Android engineers already spend their time working around React Native rather than with it.
- Startup time, app size, or platform features (widgets, Live Activities, watch apps) are costing you users or roadmap.
- You have, or are hiring, engineers who can own Swift and Kotlin code once it exists.
- The app is established enough that a quarter of migration work is a rounding error against its lifetime.
Stay on React Native when
- You are a team of one to five and shared code is what lets you ship at all.
- Nothing is actually wrong. "Shopify did it" is not a problem statement.
- Your pain is one screen or one native capability. Write a native module instead.
- Nobody on the team will own native code afterwards. Agents can write it; someone has to maintain it.