Microsoft’s hosted App Center CodePush service is gone.
App Center’s main services, including CodePush, were retired on March 31, 2025. Microsoft also published a standalone CodePush server for teams that wanted to preserve the old protocol, but that repository was archived and made read-only in May 2025. (Microsoft Learn)
So React Native teams evaluating OTA in 2026 are no longer choosing between “CodePush or nothing.”
They are choosing between several different operating models.
Some tools preserve a CodePush-shaped workflow.
Some are built around Expo’s update protocol.
Some use their own SDK, runtime, and rollout model.
Others move the whole service into infrastructure your team operates.
That makes “Which CodePush alternative is best?” a fairly weak question.
A better question is:
Which system matches the compatibility model, release controls, migration distance, recovery behavior, and ownership boundary our team actually needs?
This is not a ranking. Product behavior and plans change, and similarly named features often have different semantics. The first-party documentation referenced here was rechecked in September 2026. (Bundle Drop)
Start with the operating model
The first split is not really about features.
It is about who owns the OTA platform.
A managed service gives the mobile team a hosted control plane, artifact infrastructure, and supported release workflow.
A self-hosted system gives the organization more infrastructure control, but also makes it responsible for availability, upgrades, security patching, backups, compatibility with old mobile clients, and incident response.
Neither model is automatically better.
The important part is deciding whether infrastructure ownership is a real requirement or simply something that sounds attractive during evaluation.
The current shortlist looks roughly like this
| Option | Model | Why a team might shortlist it |
|---|---|---|
| Expo EAS Update | Managed Expo service | A natural starting point when EAS already owns builds and releases. It uses expo-updates, runtime versions, channels and branches, supports gradual rollouts, and can roll back to a previous or embedded update. Hosted usage currently meters MAU and global edge bandwidth. (Expo Documentation) |
| Codemagic CodePush | Managed CodePush service | Keeps familiar CodePush concepts such as iOS/Android apps, Staging/Production deployments, target binary versions, promotion, percentage rollout, and rollback. Codemagic currently offers both successful-install and fixed-MAU pricing models. (Codemagic Documentation) |
| AppsOnAir CodePush | Managed CodePush-style service | Preserves a CodePush-shaped CLI and release model with target binary versions, percentage rollout, rollback, release metrics, immutable releases, and code signing. (AppsOnAir) |
| React Native Stallion | Managed service, with self-hosted enterprise option | Uses its own SDK, CLI, console, promotion workflow, phased rollout, pause/rollback and adoption tooling. Hosted plans currently use MAU and bandwidth allowances, while enterprise options include self-hosted deployment. (React Native Stallion) |
| Revopush | Managed CodePush-shaped service | A candidate for teams that want a CodePush-style migration but need modern React Native/New Architecture and Expo paths. Current docs use Revopush’s own newer SDK line for modern React Native, with rollout, client/server rollback, signing, and CI/CD integrations. Hosted pricing currently combines MAU and egress allowances. (Revopush) |
| Hot Updater | Self-hostable, plugin-based | Designed for teams that want to choose their own storage, database, build and hosting providers. Its current model includes channels, rollback, compatibility/fingerprint controls, and a pluggable infrastructure architecture. (Hot Updater) |
| Standalone CodePush server | Archived self-hosted CodePush | Keeps the classic CodePush protocol available for teams prepared to maintain it themselves. The Microsoft repository is archived, read-only, and unsupported, so the team owns ongoing infrastructure and maintenance. (GitHub) |
| Bundle Drop | Managed OTA service | Uses explicit runtime compatibility, channels, staged/property-targeted rollout, local recovery, and patch/full-bundle delivery. Current pricing does not meter MAU; plans are capacity-oriented instead. (npm) |
The table is useful for building a shortlist.
It is not enough to make the decision.
Two platforms can both say “percentage rollout” while using different device identities, fallback rules, and constraints.
Two platforms can both say “rollback” while one means server-side release history and another also has device-local recovery.
Two platforms can both say “patch updates” while using very different baselines and fallback behavior.
The semantics matter more than the checkmark.
1. Test native compatibility before anything else
OTA only works safely inside a native compatibility boundary.
The installed binary must already contain every native capability the JavaScript update needs.
Different systems express this differently.
Expo uses runtime versions, and its update policy requires platform and runtime to match. (Expo Documentation)
CodePush-style systems historically use target binary version ranges.
Bundle Drop uses explicit per-platform runtime versions.
Hot Updater documents a fingerprint-based compatibility strategy.
The terminology matters less than the invariant:
an update must not reach a binary that cannot execute it.
During evaluation, deliberately change a native dependency or permission and prove that the old binary cannot accidentally receive JavaScript that depends on the new native state.
2. Measure migration distance
A team already running Microsoft CodePush has different priorities from a team starting fresh.
If preserving deployment keys, Staging/Production deployments, CLI commands, and the CodePush mental model matters, CodePush-compatible services deserve early attention.
Codemagic and AppsOnAir deliberately preserve much of that model. Revopush also offers a CodePush-shaped migration, although its current documentation uses Revopush’s newer SDK for newer React Native/New Architecture combinations. (Codemagic Documentation)
EAS Update is a different migration.
You adopt expo-updates, Expo runtime semantics, and the EAS channel/branch model. (Expo Documentation)
Bundle Drop, Stallion, and Hot Updater likewise introduce their own client and release models.
None of those is inherently worse.
But migration distance is a real engineering cost and should be treated as one.
3. Test release-selection semantics
Do not stop after proving that a 10% rollout “works.”
Test what happens to a device that is not in the 10%.
Does it stay on its current release?
Does it receive the previous eligible release?
Can another partially rolled-out release also be active?
Can the rollout percentage decrease?
How is cohort membership kept stable?
Stallion, for example, explicitly documents that the resolver checks the latest candidate and then at most the previous eligible release; if that previous release is itself partial, the user can receive no release. (React Native Stallion)
Codemagic’s CodePush model permits one active partial rollout per deployment and requires that rollout to be completed or stopped before another release proceeds. (Codemagic Documentation)
Expo’s current rollout model includes both per-update and branch-based rollouts. (Expo Documentation)
These are all legitimate designs.
They are not interchangeable.
4. Separate server rollback from device recovery
A dashboard rollback protects future release selection.
It does not automatically rescue a device that already activated a broken update and cannot get far enough to perform another successful update check.
This distinction is worth testing explicitly.
Revopush’s documentation, for example, describes both client-side automatic rollback and server-side rollback. (Revopush)
Codemagic’s CodePush documentation similarly separates automatic client rollback from manual server rollback. (Codemagic Documentation)
Bundle Drop’s current SDK records startup attempts natively, can quarantine a repeatedly failing candidate locally, and falls back to a known-good OTA or embedded bundle without requiring the network during startup. (npm)
Whatever product you evaluate, test both failure windows.
5. Treat patches as transport, not release identity
Differential delivery is useful because many OTA updates change only a small part of the final artifact.
But production fleets do not all have the same history.
Some users skip releases.
Some reinstall.
Some roll back.
Some remain outside a staged cohort.
So ask what happens when a patch baseline is unavailable.
Can the client obtain a complete artifact instead?
How is the reconstructed result verified?
What happens after an interrupted patch?
The safe release identity should not depend on one optimization path succeeding.
This is one area where product implementations differ substantially, so it deserves a device test rather than a feature-matrix check.
6. Check observability before the first incident
Once OTA exists, app version alone no longer identifies the running JavaScript.
Two users may both report native version 4.3.0 while running different OTA releases.
A useful system should let you connect:
release identity,
runtime compatibility,
download/install state,
crash reports,
rollout state,
and rollback outcomes.
If an error tracker says “4.3.0 crashed,” you should be able to determine which JavaScript artifact was actually executing.
7. Compare total operating cost, not the cheapest headline price
OTA pricing currently uses several models.
Expo meters MAU and global edge bandwidth. (Expo Documentation)
Codemagic offers successful-install and fixed-MAU models. (Codemagic Documentation)
Revopush currently combines MAU and egress allowances. (Revopush)
Stallion’s hosted tiers combine MAU and bandwidth allowances. (React Native Stallion)
Bundle Drop currently does not price plans by MAU and instead uses capacity-oriented limits such as storage, projects, and organization size. (Bundle Drop)
Self-hosted software moves part of the bill elsewhere: infrastructure, engineering time, monitoring, backups, security maintenance, and on-call.
The useful cost model therefore uses your actual release pattern:
bundle sizes,
release frequency,
number of active installations,
expected adoption,
storage retention,
and operational ownership.
A better evaluation than a feature matrix
If I were comparing OTA platforms for a production React Native app, I would put two or three candidates through the same acceptance test:
- Integrate each into an actual iOS and Android release build, not only a development client.
- Publish a harmless JavaScript + asset update and prove exact native/runtime compatibility.
- Start a partial rollout and verify cohort stability and fallback behavior for an installation that is not selected.
- Interrupt or invalidate delivery and confirm the currently working bundle stays active.
- Activate a deliberately failing candidate, test local recovery, then perform a separate server rollback.
- Verify that crash reports and release telemetry identify the exact active JavaScript artifact.
- Model one year of cost using the application’s expected update cadence and operating requirements.
The winner should be the system whose behavior your team can explain and operate.
Not the product with the longest feature table.
Where Bundle Drop fits
Disclosure: I build Bundle Drop, so it is one of the products in this comparison.
Bundle Drop is currently a managed option for Expo and bare React Native, with explicit native/runtime compatibility, named channels, staged and property-targeted release selection, native startup recovery, and hybrid patch/full-bundle delivery. Its public npm package is currently 0.7.0. (npm)
It is not the natural choice for every team.
If EAS already owns your release workflow and you want to stay inside the Expo update protocol, EAS Update should be near the top of the shortlist.
If preserving the existing CodePush mental model minimizes your migration cost, CodePush-compatible managed services deserve serious evaluation.
If self-hosting is a hard infrastructure requirement, evaluate systems designed around that ownership model.
The useful goal is not finding a universal CodePush successor.
There isn’t one.
The useful goal is choosing an OTA system whose compatibility, release-selection, recovery, delivery, observability, and ownership semantics match the way your team actually ships React Native applications.
The first-party pages I used for the verification pass are available here: Microsoft App Center retirement notice, Expo EAS Update documentation, Codemagic CodePush production controls, AppsOnAir CodePush FAQ, React Native Stallion documentation, Revopush documentation, Hot Updater documentation, and Bundle Drop npm package.
Top comments (0)