Choose an apply strategy
Compare next_start, immediate, next_resume and manual, set the strategy a mandatory release follows, and handle the reload in code.
An apply strategy decides when a downloaded update becomes the running bundle. The choices are the next start, at once, the next resume, or the moment your code picks. HotCodePush reads it as applyStrategy in hotcodepush.json, with mandatoryApplyStrategy for releases marked mandatory.
The options table on your SDK's configuration page, such as the Capacitor configuration, lists every key with its type and default. This guide picks the strategy and shows the code around the reload.
Prerequisites
- Quickstart has run, so the SDK is installed and a first release is live.
- How an update reaches a device explains the apply and the readiness gate that follows it.
1. Pick the strategy
| Strategy | When the reload happens | What the user sees | Pick it when |
|---|---|---|---|
next_start, the default | The reload happens at the next cold start. | The user sees nothing. The next start runs the new bundle. | Pick it for most apps, where an update may wait until the user opens the app again. |
immediate | The reload happens as soon as the download is verified and the app is up. | The app reloads under their hands, once per update. | Pick it when a fix must land now, and the app holds restarts with setRestartAllowed() where it has state to protect. |
next_resume | The reload happens on the first resume after at least nextResumeMinimumBackgroundSeconds in the background, 300 by default. | The user sees a reload at the moment they return. | Pick it for apps used in short sessions. |
manual | The reload happens when the app calls applyUpdate(). | The user sees whatever your code shows, such as a "restart now" button. | Pick it for apps with flows to protect, kiosks, and any app that wants to choose the moment. |
A reload replaces the running JavaScript: in-memory state is gone, and the app starts on the new bundle as after a cold start. After the reload the readiness gate runs. A bundle that does not render in time is rolled back, as Roll back a release covers.
A release created with --mandatory ignores applyStrategy and follows mandatoryApplyStrategy: immediate by default, or manual to hand the update to your code, which reads isMandatory on the release and calls applyUpdate(). There is no next_start for a mandatory release. Mandatory is transitive over skipped releases: a device that skipped a mandatory release it was eligible for treats the release it finally takes as mandatory.
sync() and downloadUpdate() take applyStrategy and mandatoryApplyStrategy for one cycle: await HotCodePush.sync({ applyStrategy: "immediate" }) applies this update at once whatever the file says. The moment is decided at download time and stored with the downloaded release.
2. Set it in hotcodepush.json
If the default next_start fits and you need no code around the reload, skip to step 4.
{
"appId": "2f1c9a7e-5b3d-4e8a-9c21-7d4f6a0b8e13",
"channel": "production",
"applyStrategy": "next_resume",
"nextResumeMinimumBackgroundSeconds": 300,
"mandatoryApplyStrategy": "manual"
}A change to the file reaches the app through a build. Devices on binaries built before the change keep the old strategy until a store release. The per-call override above changes the moment without a build.
3. Handle the moment in code
Under applyStrategy: manual the SDK keeps the download and tells you through updateDownloaded, and your code applies it when the moment is right. A mandatory release under mandatoryApplyStrategy: manual arrives through the same event, and release.isMandatory tells your code that the user may be told but not asked:
import { HotCodePush } from "@hotcodepush/capacitor-live-updates";
let pendingBundleVersion: string | null = null;
void HotCodePush.addListener("updateDownloaded", async ({ release, applyStrategy }) => {
if (applyStrategy !== "manual") {
return;
}
if (release.isMandatory) {
// Tell the user that version release.bundleVersion restarts the app, then apply.
await HotCodePush.applyUpdate();
return;
}
pendingBundleVersion = release.bundleVersion;
// Show your "Restart to update" control here; it calls applyPendingUpdate().
});
export function getPendingBundleVersion(): string | null {
return pendingBundleVersion;
}
export async function applyPendingUpdate(): Promise<void> {
const { status } = await HotCodePush.applyUpdate();
// applied: the app reloads right after this line. nothing_to_apply: nothing waits any more.
if (status !== "applied") {
pendingBundleVersion = null;
}
}Under immediate, next_resume or for a mandatory release, setRestartAllowed({ isAllowed: false }) holds the restart while the user is busy. The download goes on, and only the reload waits. The flag is not persisted: every start begins allowed.
import { HotCodePush } from "@hotcodepush/capacitor-live-updates";
export async function startCheckout(): Promise<void> {
await HotCodePush.setRestartAllowed({ isAllowed: false });
}
export async function finishCheckout(): Promise<void> {
// A restart the SDK held during the checkout runs now.
await HotCodePush.setRestartAllowed({ isAllowed: true });
}4. Check it on a device
Build the app with the new file, release a bundle to the channel the build follows, and open the debug screen on the device with HotCodePush.showDebugScreen(). It shows the running release and the downloaded one with the last check's status and reason.
Under next_start, next_resume and manual the downloaded release sits beside the running one until its moment. Under immediate the running release is the new one already. If nothing happens, see Troubleshooting.
Next steps
- Roll back a release: a rollback is mandatory by default, which is where
mandatoryApplyStrategydecides who restarts the app. - Configuration is the React Native SDK's options table. The Expo, Capacitor and Cordova pages list the same keys.
- API documents
sync(),applyUpdate(),setRestartAllowed()and the events with their result types.
Last updated on
Sign your bundles
Create a signing key pair, ship a build that trusts it, sign every upload in CI and rotate or retire keys without breaking devices in the field.
Target devices with attributes
Set attributes such as userId, tenant or plan in the app, check the reach with the audience preview and release to the devices that match.