Expo CodePush: OTA updates with Revopush 2.0

Use CodePush-compatible OTA updates in Expo with Revopush 2.0, custom release scripts, and binary diffs based on the app binary.

Expo CodePush Guide: OTA Updates with Revopush 2.0

You can keep the Expo SDK and still use a CodePush-style OTA release workflow. Revopush adds that OTA layer without asking you to stop using Expo.

EAS Update is Expo's hosted OTA service. If your release process already runs through EAS, use it.

If you already have release scripts, deployment gates, CI jobs, and rollback habits from a CodePush-style setup, moving the whole process into a different release model can be unnecessary work. Revopush 2.0 gives those projects a CodePush-compatible path through the Revopush SDK and Expo config plugin.

Revopush 2.0 can use the app binary as the base release, so the first OTA after a native release can already be a patch instead of a full bundle download.

Expo SDK is not EAS Update

EAS Update is Expo's hosted OTA service for apps using expo-updates. CodePush-style OTA is a different workflow. It is organized around apps, deployments, release commands, rollbacks, and CI/CD automation.

Revopush brings that workflow to Expo through the Revopush SDK and an Expo config plugin. It does not replace Expo SDK, Expo Router, or your existing project structure.

When existing release tooling already works

EAS Update uses Expo concepts such as branches, channels, and EAS-hosted release automation. If your team is already built around that model, there may be no reason to change it.

This usually comes up in projects that already have staging and production deployments, release commands in CI, promotion and rollback habits, internal approvals, or self-hosting requirements. Rebuilding that process around a new OTA model can be more work than the app needs.

For those apps, Revopush keeps OTA behavior CodePush-compatible while the project stays in Expo. The config plugin applies the native setup. The SDK checks for OTA updates at runtime.

Because this requires native configuration, it does not run inside Expo Go. Use a native build generated through prebuild, EAS Build, or your own native build pipeline.

Diff updates from the binary baseline

If the update system ships a full JavaScript bundle, a one-line fix may still require users to download several megabytes. That slows down rollout, hurts users on weak networks, and increases bandwidth cost.

Revopush 2.0 uses binary diff updates.

Common OTA flow:

text
App Store binary
  -> full OTA update
  -> diff update
  -> diff update

Revopush 2.0 flow:

text
App Store binary / base release
  -> diff update
  -> diff update
  -> diff update

To use Revopush 2.0 diff updates, create a base release for the specific binary version of the app. That base release is a snapshot of the JavaScript bundle and assets shipped with the IPA, APK, or AAB. Revopush uses it as the baseline for future diffs.

Users can receive small OTA patches from the first Revopush release for that binary baseline. They do not need to download a full OTA update first.

How Revopush integrates with Expo

Start by installing the SDK:

bash
npx expo install @revopush/react-native-code-push

Install the Expo config plugin:

bash
npx expo install @revopush/expo-code-push-plugin

Add the plugin to app.json, app.config.js, or app.config.ts, and add your Revopush deployment keys:

json
{
  "plugins": [
    [
      "@revopush/expo-code-push-plugin",
      {
        "ios": {
          "CodePushDeploymentKey": "YOUR_IOS_DEPLOYMENT_KEY",
          "CodePushServerUrl": "https://api.revopush.org"
        },
        "android": {
          "CodePushDeploymentKey": "YOUR_ANDROID_DEPLOYMENT_KEY",
          "CodePushServerUrl": "https://api.revopush.org"
        }
      }
    ]
  ]
}

Then apply the native configuration:

bash
npx expo prebuild --clean

After every change to Revopush settings inside the Expo config, run prebuild again so the native iOS and Android projects receive the updated configuration.

Wrap your root component with codePush()

In JavaScript, import the SDK and export your root layout or root component through codePush().

For Expo Router:

tsx
import { Stack } from "expo-router";
import codePush from "@revopush/react-native-code-push";
 
function RootLayout() {
  return <Stack />;
}
 
export default codePush(RootLayout);

For a non-router app, wrap your root component the same way:

tsx
import codePush from "@revopush/react-native-code-push";
 
function App() {
  return null;
}
 
export default codePush(App);

The wrapper lets the SDK check for an available OTA bundle and load the right JavaScript bundle for the current app binary.

Use the Revopush AI Skill instead

The AI Skill can install the SDK, add the Expo config plugin, configure placeholders for deployment keys, run prebuild, and wrap the root layout with codePush().

Use a prompt like:

Integrate Revopush OTA into my Expo project. Install the SDK and the Expo config plugin, configure deployment key placeholders in my app config, run prebuild, and wrap my root layout with codePush().

You still need a Revopush app, deployment keys, and the Revopush CLI to publish releases. The AI Skill handles the in-codebase integration, not the account or release operation.

Publish your first update

  1. Create a Revopush app and add its deployment keys to the Expo config plugin.
  2. Build the native release binary for iOS and Android.
  3. Create the Revopush 2.0 base release for that binary.
  4. Publish later JavaScript or asset changes with the Revopush CLI.

Create the base release from the binary:

bash
revopush release-native <APPLICATION_NAME> ios ./path_to_ipa/app.ipa
revopush release-native <APPLICATION_NAME> android ./path_to_apk/app.apk

Publish Expo OTA updates with:

bash
revopush release-expo <APPLICATION_NAME> android -d <DEPLOYMENT_NAME> --mandatory
revopush release-expo <APPLICATION_NAME> ios -d <DEPLOYMENT_NAME> --mandatory

After the base release exists, Revopush can generate diffs from the JavaScript bundle and assets already included in the app store binary.

Choosing the OTA service

If the Expo release process already runs through EAS Update, stay there. Use Revopush when the app needs CodePush-compatible deployments, custom CI commands, or diff updates that start from the app binary baseline.

References