
React Native OTA after CodePush: EAS Update, policy, and what growth teams still need
CodePush retirement, EAS Update migration, App Store policy, and what OTA cannot replace for growth teams (journey experimentation).
Microsoft retired App Center CodePush in March 2025. Teams that relied on it for JavaScript hotfixes now route through Expo Application Services (EAS) Update, custom OTA pipelines, or a return to store releases. That migration is necessary engineering work. It is also incomplete if your growth team still equates "over the air" with "we can test onboarding tomorrow."
OTA updates ship code. Remote flow platforms ship journey definitions. The distinction matters for subscription apps where flow iteration speed often beats bugfix velocity. This guide covers CodePush retirement fallout, EAS Update as the default CodePush alternative for React Native, store policy guardrails, and what growth teams still need after OTA is solved.
What CodePush retirement changed
CodePush let React Native teams push JavaScript bundle updates without a full App Store review. Microsoft bundled it with App Center, which also shut down. If you have not migrated, you are already on borrowed time.
| Capability | CodePush (retired) | Typical replacement |
|---|---|---|
| JS bundle OTA | Yes | EAS Update, custom CodePush fork |
| Native module changes | No | Store release required |
| Rollback | Supported | EAS channels, staged rollout |
| Dashboard | App Center (gone) | Expo dashboard or self-hosted |
| Pricing | Was bundled | Expo plans or infra cost |
Teams on bare React Native without Expo often evaluate:
- EAS Update with Expo prebuild or a brownfield integration
- Self-hosted solutions (for example,
@bravemobile/react-native-code-pushcommunity forks) - No OTA: return to weekly or biweekly store releases
None of these options replace funnel experimentation infrastructure. They replace one delivery channel for JavaScript.
EAS Update as the default migration path
For many Expo and React Native teams, EAS Update is the most documented CodePush alternative. The mental model is similar: publish a bundle, assign it to a channel, clients check for updates on launch or resume.
Migration checklist
| Step | Action |
|---|---|
| 1 | Audit current CodePush keys, deployment names, and rollback scripts |
| 2 | Map deployment names to EAS channels (production, staging, beta) |
| 3 | Add expo-updates and configure app.json / app.config.js |
| 4 | Wire CI to eas update --branch production on merge |
| 5 | Test rollback by promoting a previous update ID |
| 6 | Remove App Center SDK and dead keys from native projects |
| 7 | Document who can publish and which channel maps to prod |
Runtime behavior teams forget
EAS Update checks are asynchronous. Users on a cold start may see the previous bundle for one session before the new bundle applies. Funnel changes that depend on "instant publish" need a different layer (remote flow manifests resolve on each session).
OTA also cannot change:
- Native dependencies (RevenueCat SDK bump, new camera permission string)
- App icons, splash screens, entitlements
- Binary-linked paywall SDK major versions
Growth hypotheses that only touch JavaScript UI inside your existing navigation may fit OTA. Hypotheses that restructure onboarding order across five screens with new branch types often fit a flow platform better than bundle diffs.
App Store and Play policy: what OTA may ship
Apple and Google allow JavaScript updates within limits. Policies evolve; verify current guidelines before you publish. The practical rules teams cite:
| Allowed via OTA (typically) | Requires store review (typically) |
|---|---|
| Bug fixes in JS | New native APIs or permissions |
| Copy and styling in existing screens | Changing app primary purpose |
| Remote config driven UI in existing views | Binary changes to IAP implementation |
| A/B flags that toggle existing components | Adding new subscription products without store metadata |
Apple Guideline 3.3.2 (interpreted in release notes and reviewer feedback) expects that OTA does not turn your app into a different product. Google Play has parallel language about deceptive behavior and mandatory update mechanisms.
Risk pattern: shipping a paywall redesign via OTA that changes pricing presentation without updating store listing metadata. Billing and merchandising teams should review OTA diffs the same way they review store screenshots.
Safer pattern: OTA for bugfixes and minor UI; remote flows for journey structure; store release for native billing SDK upgrades and new SKUs.
What OTA does well vs what growth teams need
OTA solves engineering velocity for the JavaScript layer. Growth teams need experiment velocity across the funnel.
| Need | OTA (EAS Update) | Remote flows (Rheo) |
|---|---|---|
| Fix crash in checkout JS | Strong fit | Not the right tool |
| Change headline on onboarding screen 2 | Possible (needs release cadence) | Publish in seconds |
| Test 4-screen vs 7-screen onboarding | Awkward (feature flags in code) | Native experiment assignment |
| Branch on campaign / ATT / locale | Custom code per branch | Dashboard rules |
| Step-level funnel analytics | Instrument yourself | Built per screen |
| Paywall presentation | Your billing SDK UI | RevenueCat / Superwall node in flow |
Rheo does not replace EAS Update. Rheo does not ship your React Native bundle. Rheo orchestrates journeys rendered by the SDK while your app binary and OTA pipeline stay unchanged.
Combined stack diagram
Store release (binary)
└── EAS Update (JS fixes, minor toggles)
└── Rheo SDK (onboarding, lifecycle flows)
└── RevenueCat / Superwall (paywall UI + purchase)
Engineering owns the bottom of the stack. Growth owns the middle. Billing integrations own paywall presentation at the moment of purchase.
Policy-aware experiment design after CodePush
Once EAS Update is live, resist the urge to route every growth test through bundle publishes.
Problems with funnel-only OTA:
- Statistical noise: bundle version and experiment variant confound unless you version carefully
- Rollback blast radius: reverting a bad onboarding test also reverts unrelated JS fixes in the same bundle
- Review anxiety: teams self-censor journey tests that touch purchase-adjacent screens
- Analytics gaps: screen order in code does not automatically produce step funnels
Better split:
| Hypothesis type | Delivery |
|---|---|
| Navigation crash, RN version bump | EAS Update or store |
| Onboarding order and branches | Remote flow publish |
| Paywall template and pricing | RevenueCat Experiments or Superwall |
| Cancel survey and win-back | Remote flow publish |
Document this split in your growth wiki so PMs do not file "OTA request" tickets for copy changes.
Migration timeline template
| Week | Engineering | Growth |
|---|---|---|
| 1 | Stand up EAS project, parity test on staging | Inventory hardcoded onboarding screens |
| 2 | Cut over production channel, monitor crash rates | Map first remote flow channel (first_open) |
| 3 | Remove CodePush SDK | Run parity test: remote flow vs legacy path |
| 4 | Automate CI publish | First experiment on flow length (not in OTA) |
Parallel tracks prevent a common failure mode: OTA migrated in Q3, onboarding experiments still queued for Q4 store releases because nobody owned the flow layer.
CodePush alternative React Native: decision tree
Use this when evaluating tools:
- Do you only need JS hotfixes? → EAS Update (or maintained fork)
- Do you need non-engineers to change onboarding? → Add remote flows; keep EAS for code
- Do you need paywall A/B tests? → RevenueCat Experiments or Superwall; not OTA alone
- Do you need native module changes? → Store release; plan ahead
Searching for a codepush alternative react native leads to EAS Update articles. Searching for onboarding experiment velocity leads to flow platforms. Both searches are valid. They solve different problems.
Metrics after migration
Track OTA health separately from funnel health.
| Metric | OTA dashboard | Flow analytics |
|---|---|---|
| Update adoption rate | EAS | N/A |
| Crash-free sessions post-update | Sentry + EAS | N/A |
| Onboarding completion | Your product analytics | Rheo step funnel |
| Trial start rate | RevenueCat | Rheo + RC events |
| Time to publish a funnel change | N/A | Minutes |
If time-to-publish for onboarding changes is still measured in days after EAS migration, you fixed deployment but not experimentation.
Common mistakes
Mistake 1: One channel for everything. Production OTA channel carries experiments and hotfixes. Split channels or use remote flows for tests.
Mistake 2: Assuming OTA replaces store review for billing. New products and major IAP changes still go through store processes.
Mistake 3: Ignoring first-session lag. Users may not pick up the bundle until session two. Time-sensitive campaigns need manifest-based flows or forced update prompts (use sparingly).
Mistake 4: No owner for journey layer. Engineering completes EAS migration; growth still files app release tickets for copy tests.
Summary
CodePush retirement pushed React Native teams toward EAS Update and similar OTA paths. That is the right fix for JavaScript delivery. It is not the full fix for subscription growth loops that depend on onboarding, permissions, and lifecycle flows.
Use OTA for code. Use billing integrations for paywall UI. Use remote flows for journey experimentation at the speed of paid acquisition. The stack is complementary when each layer has a clear owner.
Start for free and pair Rheo journey experiments with your EAS Update pipeline.