CodePush alternative

A CodePush Alternative for React Native

Microsoft retired App Center, and with it the hosted CodePush service that a lot of React Native teams had quietly depended on for years. OTA Update covers the same job — push a JavaScript and asset bundle to apps already installed on devices, without an app-store round trip — and adds the two things teams kept asking CodePush for: rollback that repairs devices already running the bad build, and the option to run the entire server on your own infrastructure.

The same shape as CodePush

If you shipped with CodePush, the model will be familiar. An app has deployments (Staging, Production). You publish a bundle to a deployment. Installed apps check in, download it, verify it and swap it in. Nothing about your release process has to be reinvented.
  • Per-app deployments with their own keys, so Staging and Production never cross
  • A bundle targets an exact native binary version or a semver range, the way targetBinaryVersion did
  • Mandatory releases for fixes that must not be deferred
  • A CLI built for CI, so publishing is one step in a pipeline

What is different, and why it matters

The gap that hurt most with a pointer-based service was rollback. Flipping the "current release" pointer stops the bad bundle reaching anyone new — but every device that already installed it stays broken, because those devices are not going to ask for anything older than what they have.
  • A rollback republishes the last good bundle as a new mandatory release at 100%, and disables the bad one — so devices already on the bad build take the fix on their next check
  • The stored bundle is reused rather than re-uploaded, so the rollback is immediate
  • The SHA-256 published with a release is verified before the archive is unpacked, and extraction is zip-slip protected
  • A build that never confirms it booted is reverted automatically on the device

Migrating an app that used CodePush

The work is mostly mechanical: swap the SDK, take a key per channel instead of per app, and point your publish step at the new CLI. The quickstart walks the whole path, and the bare React Native and Expo guides cover the native side for each project type.
  • Install @otaupdate/react-native and remove the old client
  • Create the project here and copy each channel key into the matching build config
  • Replace the publish command in CI with the ota CLI — see the CI guide
  • Ship a no-op bundle to a 1% rollout first and watch adoption before going wider

CodePush and OTA Update, side by side

App Center CodePushOTA Update
StatusRetired as a hosted serviceActively developed
Rollback reachStops new installs of the bad bundleRepublishes the good bundle as mandatory, so devices already broken are repaired
Staged rolloutPercentage rolloutPercentage rollout with deterministic per-device bucketing
Self-hostingServer code open-sourced; you assemble and operate itSupported deployment: docker compose up -d, or use the managed service
IntegrityBundle hashSHA-256 verified before unpack, zip-slip protected extraction
Where CodePush still wins: years of accumulated Stack Overflow answers, blog posts and CI recipes. If you hit an edge case at 2am, there is simply more written about CodePush than about anything that replaced it — including us. We are trying to close that with the docs, but it is an honest gap.

Frequently asked questions

Is CodePush really gone?
The hosted App Center service was retired. Microsoft open-sourced the server, so you can run a CodePush server yourself — but you are then responsible for standing it up, operating it and keeping it patched, and the managed product teams relied on no longer exists.
Can I keep using my existing bundle build step?
Yes. The bundle you publish is the same JavaScript bundle and asset set your build already produces. What changes is the client SDK and the command that uploads it.
Does this work with bare React Native as well as Expo?
Both. There is a config plugin for Expo and a manual native setup for bare React Native, covering iOS and Android.
What can I not ship over the air?
Anything that is not in the JavaScript bundle or its assets. A new native module, a new permission, an SDK bump or an Info.plist change still needs a store release. Shipping JS that calls a native API the installed binary does not have will crash the app, which is what binary version targeting exists to prevent.

Keep reading

Ship a fix without waiting for review.

Free to start. Publish a bundle, stage it to a percentage of devices, and roll it back for everyone if it goes wrong.