HotCodePush

Ship every commit

Run npx hotcodepush release create after the build on every merge to main, with the API token and the signing key held as CI secrets.

To ship every commit, your pipeline runs one command after the build on every merge to main. HotCodePush uploads the build, signs it, releases it to the channel and records the commit it came from. Devices take it on their next check.

npx hotcodepush release create --channel production --bundle-version "$(git rev-parse --short HEAD)" --yes

Before the pipeline

  • The quickstart has run: hotcodepush.json is committed, the SDK is in the app and a store build carries the app's fingerprint.
  • The app has a signing key from Sign your bundles.
  • You hold an API token from the console's API tokens page.
  • The CLI is pinned as a dev dependency, so npm ci installs the version the team tested:
npm install --save-dev --save-exact hotcodepush

The three steps

Every recipe has the same three steps.

  1. Check out the commit: the CLI reads the commit from the checkout and records it with the bundle.
  2. Build the app: a React Native or Expo app skips this step, since the CLI packages the bundle per platform inside the upload, one release per platform. A Capacitor or Cordova app runs its own build, npm run build.
  3. Release: the line above. The short commit hash in --bundle-version is the name you look for in the release log and in release list. The --yes flag answers the confirmation a pipeline cannot answer. See the global options.

The release applies within about a minute. How an update reaches a device explains the delay. release lists every flag.

One recipe per provider carries the complete setup and the secrets to set: Azure DevOps, Bitbucket Pipelines, Bitrise, Capawesome Cloud, Codemagic, EAS Build, Gitea Actions, GitHub Actions and GitLab CI/CD. Xcode Cloud registers the iOS store build and leaves the release to one of them.

The secrets a pipeline holds

SecretHoldsWhich jobs
HOTCODEPUSH_TOKENHolds an API token from the console's API tokens page.Every job that talks to HotCodePush reads it.
HOTCODEPUSH_SIGNING_KEYHolds the content of the private key file signing-key create wrote.The jobs that upload read it, never the dry run.

A token expires, after 30 days by default, so pick a longer expiry for a pipeline. The tokens page shows each token's last request, which is where you look when CI stops working.

The CLI reads the key with or without its PEM header and footer lines, on one line too. A provider whose secrets are single-line takes the base64 body:

grep -v -- '-----' hotcodepush-private-key.pem | tr -d '\n'

A pull request job that checks the build without releasing holds the token alone: --dry-run signs nothing and uploads nothing. It checks the size limit and prints the audience the release would reach:

npx hotcodepush release create --channel production --dry-run

The three disciplines

  • Forward-compatible data: a rollback, a revocation, a channel switch through setChannel or the SDK's own rollback runs older code over data the newer code wrote. An over-the-air (OTA) update adds a column, a key or a store and never renames, removes or retypes one. A migration runs forward only, and code keeps fields it does not know. What cannot keep that waits for the store release.
  • Native changes wait for the store: an OTA update replaces the web or JavaScript layer, never the native one. A device takes a release only when its store build matches the release's fingerprint. Compatibility explains what it covers. A commit that touches native code produces a bundle no store build in the field matches, and the dry run shows reaches 0 of 10,000 active devices.
  • Rollout progression: --rollout-percent 10 --progression on the line starts every merge small and widens it on its own, and auto-pause stops a bad one. Roll out gradually has the schedule and the counters.

Which commit is live

The console's Releases page answers in its Commit column: the short sha and the subject, linked to the commit on the remote. With the label set to the short hash, the Bundle and Commit columns name the same thing, and release list reads the same way.

A bundle uploaded from a dirty working tree is marked as such. The build step wrote into tracked files. Find what it changed and ignore or commit it. Bundles and releases has what each upload records and the flags that override it.

Next steps

  • GitHub Actions has the complete workflow, the secrets and the fork guard.
  • Test with preview channels gives every pull request a channel, released from the same pipeline, with a QR code for testers.
  • Roll out gradually: raise a rollout by hand, pause it and read the counters behind auto-pause.
  • Troubleshooting lists the causes when the job is green and a device did not take the release.

Last updated on

On this page