Rollback
What Rollback Is
Rollback is how Bundle Drop moves users off a problematic OTA bundle and back to the previous working version.
This is not a separate "negative update" that you have to build and publish. It is a revert to the previously active bundle for that channel.
Bundle Drop gives you two layers of protection:
- Manual rollback you trigger from the dashboard when you spot a bad release.
- Automatic crash protection on the device, which records OTA launch attempts before React Native starts and reverts an update that repeatedly fails to become healthy.
How Rollback Works
From the client point of view, rollback means:
- the current OTA bundle stops being the active target
- the app returns to the previous bundle it was on
- if there is no previous OTA bundle, the app falls back to the native bundle that shipped with the app binary
That means rollback can return users either to an older OTA bundle or all the way back to the native bundled version.
Where to Do It in the Dashboard
Rollback is handled from the dashboard on a channel's Bundles page.
The typical path is:
- open your project
- open the channel you want to manage
- go to that channel's Bundles page
- choose the bundle you want to roll back
Rollback is channel-scoped, so it affects that channel rather than every channel in the project.
When Teams Use It
Rollback is useful when:
- a release causes crashes or broken behavior
- you need to quickly return users to the last stable version
- you do not want to wait for a replacement OTA bundle to be prepared
What the Client Needs to Know
- rollback reverts users to the previous working bundle
- if the previous working version is the native bundle, the app falls back to that native bundle
- rollback does not require publishing a special reverse bundle
Automatic Crash Protection
In addition to dashboard-triggered rollback, Bundle Drop includes native automatic crash protection on the device. Before React Native receives a candidate bundle path, native code records a unique launch attempt. If that attempt never reaches its configured health boundary, the next distinct app launch counts it as incomplete. After repeated incomplete attempts, the SDK quarantines the candidate and restores the previous native-proven healthy OTA bundle — or the original embedded bundle when no eligible previous OTA exists.
How It Works
After an OTA update is applied, Bundle Drop treats the new bundle as a startup candidate:
- native code records a candidate launch before returning its bundle path to React Native
- the next distinct launch counts a still-incomplete attempt; repeated resolver calls in one process do not
- below
maxCrashCount, the SDK retries the candidate with a new attempt identity - at
maxCrashCount, the SDK quarantines the candidate and reverts to the last native-proven healthy bundle - if the previous bundle cannot be fully verified or is locally revoked, the SDK launches the embedded bundle
- the failed hash remains blocked for future checks, downloads, manual installs, and applies on that installation
Because recovery state is native, import-time JavaScript failures, missing native-module calls, React initialization failures, native crashes, watchdog termination, and process death can all leave an observable incomplete attempt. Recovery occurs on a later cold launch; Bundle Drop cannot repair a failure in the embedded binary or one that happens before its native bundle resolver executes.
When the device checks for updates again, Bundle Drop avoids selecting an update that already failed on that device. This does not revoke the bundle for other devices. To ship a fix for that device, publish a new bundle or keep the current bundle. Do not retry the locally failed update on the same device.
Default Behavior
By default, native recovery marks a newly launched OTA bundle healthy after React content appears and the configured healthyAfterSec delay survives in the same process. A process that exits during the delay remains incomplete.
Bundle Drop still protects against repeated incomplete startup attempts. If a candidate repeatedly fails to become healthy, the SDK rolls back to the previous native-proven healthy bundle or to the embedded bundle.
If your app has a clear startup readiness point, you can use manual health reporting. In manual mode, Bundle Drop waits for your app to call BundleDrop.reportHealthy() before treating the candidate as safe to keep.
In manual health mode, forgetting to call
reportHealthy()can cause a healthy OTA update to roll back after repeated incomplete attempts classified on later distinct launches. Use manual mode only when your app has a reliable readiness point.
Configuration
You can customize rollback health behavior in your bundle.drop.config.js:
module.exports = {
// ... other config
rollback: {
maxCrashCount: 3, // incomplete attempts before rollback (default: 3)
healthCheckMode: "auto", // "auto" or "manual" (default: "auto")
healthyAfterSec: 0, // auto mode delay before marking healthy (default: 0)
},
};healthyAfterSec is only used in auto mode. Increasing it can catch more early startup failures, but it also extends the period in which process termination leaves the launch incomplete. Keep it short unless you intentionally want stricter startup validation.
Setting maxCrashCount to 0 disables launch-health classification, retries, quarantine, and automatic rollback. Integrity, runtime compatibility, existing quarantine, and the latest locally persisted revocation checks still apply.
Manual Health Reporting
Use manual health reporting when your app should decide exactly when startup is healthy:
module.exports = {
// ... other config
rollback: {
healthCheckMode: "manual",
maxCrashCount: 3,
},
};import { useEffect } from "react";
import { BundleDrop } from "@gfean/react-native-bundle-drop";
BundleDrop.init({
environment: "production",
policy: "on-next-launch",
});
export function App({ appReady }: { appReady: boolean }) {
useEffect(() => {
// Replace appReady with your own startup readiness condition.
if (!appReady) return;
void BundleDrop.reportHealthy();
}, [appReady]);
return <RootNavigator />;
}reportHealthy() asks native recovery to commit the exact hash and launch-attempt identity captured by the running React runtime. Repeated matching calls are idempotent, while stale calls from an older attempt are ignored. It is not crash analytics and does not replace your monitoring tools.
Startup recovery is offline. "Not revoked" means absent from the most recent signed revocation state already persisted on the device; the SDK does not block launch on a network request.
Crashes after an attempt has been committed healthy do not trigger automatic startup rollback. Diagnose them through normal crash reporting and use fix-forward or explicit rollback controls.
Related Docs
- For release tracks, see Channels.
- For gradual release control, see Staged Rollouts.
- For publishing bundles, see Uploading.
