HotupdaterHot Updater
React Native API

wrap

`hotUpdater.wrap` checks for an update when the app's root mounts, stages standard updates for the next start, and reloads forced updates by default.

Usage

wrap is a method of the instance HotUpdater.init returns. Wrap the app's root with it, and it checks for an update when the root mounts. The update server, request headers, plugins, and onError come from HotUpdater.init; wrap takes only the update flow.

App.tsx
import { Text, View } from "react-native";

import { hotUpdater } from "./src/hotUpdater"; 

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default App; 
export default hotUpdater.wrap({ 
  updateStrategy: "appVersion", // or "fingerprint"
})(App);

src/hotUpdater.ts is the module that calls HotUpdater.init and exports the instance, as init shows.

A standard update is prepared and staged without reloading the React Native runtime currently in use. It becomes active the next time that runtime starts, normally on the next cold app launch. An update with shouldForceUpdate: true, including a bundle-changing server-directed rollback, is prepared and then reloads the app by default. Set reloadOnForceUpdate: false when the current session must remain uninterrupted.

To choose when the app checks, call hotUpdater.checkForUpdate() from your own flow instead, as the custom update guide shows. Use one of the two for a launch, so the app does not check twice.

Configuration reference

OptionTypeRequiredDescription
updateStrategy"appVersion" | "fingerprint"YesUpdate detection strategy
fallbackComponentReact.FC<HotUpdaterFallbackComponentProps>NoUI shown instead of the root during a check and a forced update
onProgress(progress: number) => voidNoCallback fired during bundle download (0-1)
reloadOnForceUpdatebooleanNoReload after a forced update is prepared (default: true)
onUpdateProcessCompleted(response) => voidNoCallback when the update process completes

Errors during the flow go to the onError handler of HotUpdater.init.

fallbackComponent

While the update check runs, the fallback replaces the app's root.

  • For a forced update, the fallback stays until the bundle is downloaded, and progress updates as it downloads.
  • For a standard update, the fallback shows only during the update check.

Without a fallbackComponent, the root renders at once and the bundle downloads without blocking the screen.

Props:

  • progress: Download progress (0-1, e.g., for a progress bar)
  • status: Update state (CHECK_FOR_UPDATE or UPDATING)
  • message: Message from the server, or null
  • artifactType: "diff" or null before progress starts
  • details: Per-file diff progress, or null

The progress fields have the same shape as useHotUpdaterStore.

App.tsx
import { Text, View } from "react-native";

import { hotUpdater } from "./src/hotUpdater";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default hotUpdater.wrap({
  updateStrategy: "appVersion",
  fallbackComponent: ({ progress, status, message }) => ( 
    <View
      style={{
        flex: 1,
        padding: 20,
        borderRadius: 10,
        justifyContent: "center",
        alignItems: "center",
        backgroundColor: "rgba(0, 0, 0, 0.5)",
      }}
    >
      {/* You can put a splash image here. */}

      <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
        {status === "UPDATING" ? "Updating..." : "Checking for Update..."}
      </Text>
      {message && (
        <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
          {message}
        </Text>
      )}
      {progress > 0 ? (
        <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
          {Math.round(progress * 100)}%
        </Text>
      ) : null}
    </View>
  ),
})(App);

reloadOnForceUpdate

When wrap receives an update with shouldForceUpdate: true, it prepares the selected transition and reloads the app, after HotUpdater.init has read the current launch. Bundle-changing server-directed rollbacks also use this path. If set to false, the current React Native runtime keeps running and the staged update becomes active on the next runtime start or after a later hotUpdater.reload() call.

This option only controls wrap. updateBundle() never reloads the app by itself. The reload follows hotUpdater.setReloadBehavior().

App.tsx
export default hotUpdater.wrap({
  updateStrategy: "appVersion",
  reloadOnForceUpdate: false, // Keep the current session running
})(App);

onUpdateProcessCompleted

Reports when wrap has finished handling the update.

For a standard update, wrap invokes this callback after starting the non-blocking download, not after the download finishes. Do not use it as a download-readiness signal.

UP_TO_DATE means the check returned no transition. A failed check can also return null after calling init.onError, so this status alone does not prove that the server was reached or the app is current.

Callback arguments:

PropertyTypeDescription
status"ROLLBACK" | "UPDATE" | "UP_TO_DATE"The status of the update process
shouldForceUpdatebooleanWhether the update process is forced
idstringThe selected update's console ID
messagestring | nullThe message of the update process
App.tsx
export default hotUpdater.wrap({
  updateStrategy: "appVersion",
  onUpdateProcessCompleted: ({ status, shouldForceUpdate, id, message }) => { 
    console.log("Update process completed:", status, shouldForceUpdate, id, message);
  },
  onProgress: (progress) => { 
    console.log("Bundle download progress:", progress);
  },
})(App);

How it works

The client reads a shared Release Catalog, selects a transition on the device, and resolves the artifact when staging is needed. See how updates work for the full lifecycle.

Flag behavior

Update ResponseRuntime BehaviorHow to Enable
shouldForceUpdate: falseStages the selected bundle without reloading the current runtime; it becomes active on the next runtime start.Default setting
shouldForceUpdate: truewrap reloads after preparing the selected transition; reloadOnForceUpdate: false defers it to a later start.Use --force-update or the console; bundle-changing rollbacks also return it.

On this page