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.
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 automatic crash protection on the device. If a new OTA update repeatedly fails before Bundle Drop can mark it healthy, the SDK rolls back to the previous stable version — or to the original native bundle if no previous OTA version exists. This check runs when JavaScript reaches BundleDrop.init(), so call BundleDrop.init() as early as possible in app startup.
How It Works
After an OTA update is applied, Bundle Drop treats the new bundle as a startup candidate:
- each launch before the candidate is marked healthy counts as an unconfirmed startup
- when unconfirmed launches reach
maxCrashCount, the SDK automatically reverts to the last known good bundle - the failed bundle is remembered locally on that device and blocked for future checks, downloads, manual installs, and applies
- once an update is marked healthy, the crash counter resets
This protects against repeated startup loops that reach Bundle Drop initialization. Crashes before JavaScript reaches BundleDrop.init() are outside this local health check.
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, Bundle Drop marks a newly launched OTA bundle healthy on the next JavaScript tick after startup initialization. This keeps the default behavior conservative and avoids rolling back healthy releases because of normal app interaction after startup.
Bundle Drop still protects against repeated unconfirmed startups. If a candidate launches repeatedly without being marked healthy, the SDK rolls back to the previous bundle or to the native bundled version.
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 unconfirmed 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, // unconfirmed launches 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 means Bundle Drop may treat crashes before that delay ends as unconfirmed startup failures. Keep it short unless you intentionally want stricter startup validation.
Setting maxCrashCount to 0 disables crash-loop rollback.
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 { BundleDrop } from "@gfean/react-native-bundle-drop";
BundleDrop.init({
environment: "production",
policy: "on-next-launch",
});
import { useEffect } from "react";
import { BundleDrop } from "@gfean/react-native-bundle-drop";
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() marks the currently running OTA bundle safe to keep on this device. It is not crash analytics and does not replace your monitoring tools.
Related Docs
- For release tracks, see Channels.
- For gradual release control, see Staged Rollouts.
- For publishing bundles, see Uploading.
