HotCodePush

Installation

Set up @hotcodepush/expo-ota-updates with an AI agent, with npx hotcodepush init or by hand with its config plugin, prebuild and a release build.

Install @hotcodepush/expo-ota-updates in one of three ways: let an AI agent do it, run npx hotcodepush init, or follow the steps by hand. You need an Expo app on a supported SDK, a development build with expo-dev-client or a release build, and an app in the console. Expo Go carries no native module of the SDK.

Install the HotCodePush skills:

npx skills add hotcodepush-team/skills

Then paste the prompt into your coding agent:

Set up HotCodePush in this project: install the skills with `npx skills add hotcodepush-team/skills`, then run the hotcodepush-init skill and the hotcodepush-release skill, following https://hotcodepush.com/docs/ai.

The agent installs the SDK, creates the app and ships a first update. Agent skills explains what the agent does.

Set up with the CLI

npx hotcodepush init

init installs the package, writes hotcodepush.json, adds the plugin entry to the app config and signs you in. The init reference lists every step and the manual step it hands you when it cannot edit a file. Run it again after a manual step: it finishes only what is missing.

Manual setup

If init already ran, skip to the prebuild in step 3.

1. Install the package

npm install @hotcodepush/expo-ota-updates
npm install --save-dev hotcodepush

Declare the Expo package alone: it brings the React Native module @hotcodepush/react-native-code-push, and every import comes from the Expo package. The CLI is a dev dependency: the build step runs npx hotcodepush inside every native build.

2. Add hotcodepush.json

hotcodepush.json
{
  "appId": "4f2b7c9e-8d31-4a6e-9b0f-2c5d7e8a1b34",
  "channel": "production"
}

appId is on the app's page in the console, and channel is the channel this build follows. Every other key has a default. Configuration lists them. app.json carries only the plugin entry, never an option.

3. Add the config plugin and prebuild

app.json
{
  "expo": {
    "plugins": ["@hotcodepush/expo-ota-updates"]
  }
}

init adds the entry to app.config.json where the project has one, otherwise to app.json. In a project whose app config is code, add it yourself. Then remove expo-updates, or set updates.enabled to false in the app config, since each of the two decides which bundle the app runs. The prebuild refuses the pair.

npx expo prebuild

At every prebuild the plugin wires the build step and both native hosts. What the step writes and needs is on binary. A store build needs HOTCODEPUSH_TOKEN in its environment. After upgrading the package, run npx expo prebuild --clean once.

Where a file of Expo's template has changed past what the plugin knows, the prebuild fails and names the file and what it looked for:

FileWhat the plugin looks for
the Xcode projectLooks for the "Bundle React Native code and images" phase, which the binary step runs after.
AppDelegate.swiftLooks for bundleURL() returning the embedded main.jsbundle, which becomes HotCodePush.bundleURL().
PodfileLooks for the use_native_modules! line, which the HotCodePushCore pod follows.
app/build.gradleLooks for a Groovy build file, the language of the line that applies hotcodepush.gradle.
MainApplication.ktLooks for a React host built with Expo's ExpoReactHostFactory.getDefaultReactHost(), which becomes HotCodePushReactHost.getDefaultReactHost().

4. Build and verify

Build in release, run the app and check the setup:

npx expo run:ios --configuration Release
npx expo run:android --variant release
npx hotcodepush doctor

The development build, npx expo run:ios or run:android, is a debug build and takes no updates. Then doctor reports each check as ok, skipped or failed, with the step that repairs a failure. doctor lists the checks.

5. Release a first update

Change something visible, then release it to the channel. release create bundles each platform with expo export:embed:

npx hotcodepush release create

The device applies the release at its next start. release has every option. If nothing happens, see Troubleshooting.

Platform notes

  • Expo Go and the web: the package loads, and every method rejects with one error saying the SDK needs a development or release build, and useUpdates() keeps the embedded state. Errors has the detail.
  • Debug builds, the development build among them, embed no bundle and take no updates, whatever isEnabledInDebugBuilds says. Every cycle answers skipped with build_debug. Test an update in a release build.
  • Builds: a Release run of expo run:ios writes the file and creates no binary, so its first update is the full pack. The Android release variant creates the binary and needs a login or HOTCODEPUSH_TOKEN. So do an archive and EAS Build, with the token in the build's environment.
  • Android: the SDK's manifest declares INTERNET and ACCESS_NETWORK_STATE, nothing to add. An app that sets android:fullBackupContent or android:dataExtractionRules itself hits a manifest merger conflict. Keep your rules, add tools:replace for the attribute on <application>, and exclude hotcodepush/ under domain="file" in both <cloud-backup> and <device-transfer>.
  • Privacy: the SDK ships its privacy manifest, nothing to add. Privacy and device data has the App Privacy answers.

Next steps

  • Configuration lists every key of hotcodepush.json and the strategies that decide when an update is checked, downloaded and applied.
  • API documents sync(), the stage methods, useUpdates(), the events and every status and reason.
  • Sign your bundles sets up a key pair whose public key goes into hotcodepush.json, so a device applies only what you signed.

Last updated on

On this page