EAS Build
Store builds on EAS Build that register themselves with HotCodePush through an EAS secret, and an EAS Workflows job that releases every push to main.
To ship every commit from EAS Build, the store build registers itself with HotCodePush through HOTCODEPUSH_TOKEN, a secret of its profile's EAS environment. An EAS Workflows job on every push to main releases the over-the-air (OTA) update.
Ship every commit has the prerequisites and the three disciplines. This page carries the EAS settings and the workflow, for an Expo app. An app still on expo-updates removes it and its config first, as Migrate from EAS Update shows, since the prebuild refuses the pair.
EAS uploads no git-ignored file and installs dev dependencies, so the committed hotcodepush.json and the pinned CLI reach the build.
Secrets to set
Both are EAS environment variables with secret visibility, unreadable outside EAS and redacted in the logs.
| Secret | Holds |
|---|---|
HOTCODEPUSH_TOKEN | Holds an API token from the console's API tokens page. |
HOTCODEPUSH_SIGNING_KEY | Holds the base64 body of the private key file signing-key create wrote, on one line. Leave it out until the app has a key. |
eas env:set --name HOTCODEPUSH_TOKEN --value <token> --environment production --environment preview --visibility secret
eas env:set --name HOTCODEPUSH_SIGNING_KEY --value "$(grep -v -- '-----' hotcodepush-private-key.pem | tr -d '\n')" --environment production --visibility secretEvery environment whose profiles make release builds holds the token: production, and preview for internal distribution builds. A CI provider's secret never reaches the builder, and eas build from another CI reads the token from EAS too.
The pipeline
The store builds
Each build profile names its environment, the EAS variables the build reads. Under a profile's env, HOTCODEPUSH_CHANNEL points its builds at another channel, as Set up environments and tenants shows. The channel must exist, and env holds no secret.
{
"cli": {
"appVersionSource": "remote"
},
"build": {
"production": {
"environment": "production",
"node": "22.23.3",
"autoIncrement": true
},
"preview": {
"extends": "production",
"environment": "preview",
"distribution": "internal",
"env": {
"HOTCODEPUSH_CHANNEL": "staging"
}
}
}
}- The build step registers every build but a development or simulator one. EAS sets
CI, so a store build without the token fails. See binary. autoIncrementwith the remote version source gives every build a build number of its own (App version management). A store build whose version and build number another binary already holds fails the build.- On SDK 55 the images ship Node.js 20 and the CLI needs 22:
productionsets"node": "22.23.3", whichpreviewinherits.
Run eas build --platform all --profile production. Then npx hotcodepush binary list shows the builds that registered.
The OTA release
A workflow under .eas/workflows runs the release job on every push to main. Its push trigger needs the GitHub repository linked to the EAS project (Get started with EAS Workflows). Skip Expo's deploy template and eas update:configure, since both install expo-updates again.
name: Release to production
on:
push:
branches: ['main']
defaults:
tools:
node: '22'
jobs:
release:
environment: production
steps:
- uses: eas/checkout
- uses: eas/install_node_modules
- name: Release to production
run: npx hotcodepush release create --channel production --bundle-version "$(git rev-parse --short HEAD)" --yes --jsonenvironment: productionhands the job the token, the key and theEXPO_PUBLIC_*values the store build embedded.defaults.tools.nodeinstalls Node.js 22 through nvm (Syntax for EAS Workflows).- No build step: the CLI packages the bundle per platform inside the upload.
- The checkout is on a branch, so the CLI records
mainwithout--git-ref. release lists every flag.
A failed release fails the job and prints the error as JSON, and the error catalog names the fix. A green job and a device that did not take the release is the other case. See Troubleshooting.
From another CI, that provider's recipe works unchanged, and the token is that CI's own secret. Before the release line, npx eas-cli env:pull --environment production --non-interactive, with EXPO_TOKEN set, writes the environment's plain-text and sensitive variables, EXPO_PUBLIC_* included, to .env.local.
Next steps
- Ship every commit names the three disciplines a pipeline that ships every commit keeps.
- Roll out gradually puts
--rollout-percent 10 --progressionon the release line and explains the counters behind auto-pause.
Last updated on
Codemagic
A variable group that lets every store-build workflow register its build, and a workflow on push to main that releases every merge, both in codemagic.yaml.
Gitea Actions
A release.yml under .gitea/workflows that releases every push to main to production with the HotCodePush release action, with the bare CLI line beside it.