The native-build path: getting AppX apps to TestFlight without writing native code
Expo Go is a preview surface, not a release artifact. Building the path to .ipa and .aab via EAS — what's shipped, what's still rough, and what we won't do.
AppX team ·
An AppX user types "make me a habit tracker," watches a QR code appear, scans it with Expo Go, and the app is in their hand. The whole loop takes seconds. Edit a screen via chat, the change lands on the phone before they put it back down. That is the preview. It is not the App Store.
A preview is not a release. A user who wants their app on TestFlight or the Play Store needs something the Expo Go shell cannot produce: a signed .ipa or .aab, built against a real bundle identifier, signed with real developer credentials, accepted by Apple's or Google's submission pipeline. That is the native-build problem. We are building the path. Here is what is there today and what is not.
Today
Every AppX user gets the preview path the moment they click generate. Backend pushes generated source files into a warm container, Metro bundles, a QR code appears in the chat panel, the user scans it with Expo Go on their phone. The app is live, hot-reloading over Metro, with a feedback loop of about 100 milliseconds from chat edit to phone re-render. No Apple Developer account. No Xcode. No provisioning profile. No keychain. The user only has a phone.
This is the moat. Most app-builder products show you a web preview pretending to be a phone. AppX puts the app on the actual device the user will ship to. That part works.
The gap
Expo Go is a host shell. The user is not running their app — they are running Expo Go, which is loading their app's JavaScript bundle. Apple does not accept Expo Go as a release artifact. To ship, the user needs the JavaScript bundled into a native binary, the binary signed with a developer certificate, the certificate tied to a provisioning profile that lists allowed devices or App Store distribution. None of that is in the preview path. The preview path was deliberately built to avoid all of it.
A user can love their AppX app, want to ship it tomorrow, and still hit a wall the moment they leave the preview surface. Closing that wall is the native-build path.
Why EAS Build
We do not want to operate a build farm. iOS builds need Xcode on Apple hardware. Android builds need Gradle, a JDK, and a sane Android SDK install. Maintaining agent pools for both, keeping them on current toolchain versions, handling provisioning quirks per Apple release — that is a full team's worth of work and zero of it is differentiated for AppX users. Expo already runs that infrastructure for the entire React Native ecosystem. We integrate with EAS Build instead of rebuilding it.
The trade is honest. We outsource the build executor to Expo's cloud. We keep ownership of everything that touches the user — project configuration, asset generation, status reporting back into chat.
What's already shipped
A basic "Export to EAS" flow is live in the AppX UI. The user links their Expo account, AppX serializes the generated project, EAS runs the build on its own hardware, and the resulting artifact lands back in the user's Expo dashboard. For users who already know what an eas.json is, this works today.
That last sentence is the problem.
What's still rough
Icon and splash assets. AppX generates code; it does not yet generate the ~30 icon variants iOS expects, the adaptive icon foreground/background pair Android wants, or a splash screen sized for every device class. A user with a logo can paste it into Expo's asset config and let EAS do the rest, but that step is manual today. It should not be.
Bundle identifier. Every native app needs a reverse-DNS identifier — com.yourname.habittracker — registered against an Apple Developer account before TestFlight will accept the build. We surface the form. We do not yet validate that the identifier is unclaimed, well-formed, or matches the account the user just linked. A bad bundle ID surfaces as an opaque EAS error 12 minutes into the build, which is the worst place to surface it.
Signing credentials. Apple's certificate-and-profile model is the highest-friction part of the whole pipeline. EAS has a managed credentials flow that handles most of this if the user grants enough access; otherwise, the user is back on the Apple Developer Portal generating certificates and downloading .mobileprovision files by hand. We are investigating how much of that we can route through EAS managed credentials by default.
Build progress in chat. A native build takes 10 to 15 minutes. Today the user clicks build and is shown a status page they have to refresh. The AppX chat panel — the surface where they spent every previous minute of the product — goes quiet. That is wrong. Build progress should stream into the chat with the same EngineActivityCard pattern we already use for generation runs.
The longer-term roadmap
Asset generation is the obvious next slice. A user pastes a logo into AppX, a Sharp- or Resvg-backed pipeline emits the full iOS icon set, the Android adaptive pair, and a splash screen with the correct safe-area math for every device class. The Expo asset config gets written automatically. The user never opens a graphics tool.
One-tap store submission is the slice after that. Once a build artifact lands, the same Expo account linkage that uploaded the project should let AppX initiate the App Store Connect or Play Console upload directly. The user is one button away from review.
Native module routing is further out and more interesting. When the AI generates code that uses a native capability Expo Go does not include — certain camera APIs, Bluetooth Low Energy, some background tasks — the preview path stops being viable for that specific app. The right behavior is for AppX to detect the unsupported import, automatically route that project through an Expo development build instead of Expo Go, and silently expand what the preview can run. The user should not have to know the difference.
What this is NOT
This is not a way around App Store review. We can get an app to TestFlight; Apple still reviews. We can produce an .aab; Google still has a publishing process. The native-build path closes the technical gap, not the platform-policy gap.
This is also not a path for arbitrary native apps. AppX targets the Expo SDK surface on purpose. If a user wants something Expo does not wrap — a custom native module written in Swift, a fork of React Native, a non-Expo build system — they are inside a normal React Native project with all the complexity a normal React Native project carries. We are not pretending to solve that.
Closing
The preview is the magic. The native build is the responsibility. A user who falls in love with their AppX app and then cannot ship it has gotten the worst version of the product. Closing that gap is not glamorous work — most of it is icon math, signing flows, and turning 10-minute build logs into 10-minute chat messages — but it is the work that decides whether AppX is a fun toy or a path to a real app on a real phone in a real store. We are building toward the second one.