HotupdaterHot Updater
React Native API

wrap

`HotUpdater.wrap` stages standard updates for the next app start and reloads force updates by default.

Usage

Important: Configure Hot Updater with either HotUpdater.wrap or HotUpdater.init before calling update APIs. This enables automatic crash detection and rollback. Update methods will throw an error if neither API is used.

HotUpdater.wrap configures automatic updates. The automatic mode is the default, so updateMode is no longer needed.

A standard update is prepared and staged without reloading the React Native runtime currently in use. Once staging finishes successfully, it becomes active the next time that runtime starts, normally on the next cold app launch. In the automatic HotUpdater.wrap flow, responses with shouldForceUpdate: true, including bundle-changing server-directed rollbacks, prepare the selected transition and then reload by default. Set reloadOnForceUpdate: false when the current session must remain uninterrupted.

Automatic Updates

Use this for apps that want automatic OTA updates. This is the standard approach with full update management.

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

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

export default HotUpdater.wrap({ 
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  // If you need to send request headers, you can use the `requestHeaders` option.
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
})(App);

Manual Updates

Use HotUpdater.init for manual update flows. Initialize once with HotUpdater.init, export your root component directly, then call checkForUpdate or updateBundle when needed.

import { HotUpdater } from "@hot-updater/react-native";

HotUpdater.init({
  baseURL: "<your-update-server-url>",
});

Then use checkForUpdate or updateBundle manually when needed:

import { HotUpdater } from "@hot-updater/react-native";
import { useEffect } from "react";

function App() {
  useEffect(() => {
    const checkUpdate = async () => {
      const updateInfo = await HotUpdater.checkForUpdate({
        updateStrategy: "appVersion", // Required: specify update strategy
        requestHeaders: {
          Authorization: "Bearer <your-access-token>",
        },
      });

      if (!updateInfo) {
        console.log("No update found");
        return;
      }

      await updateInfo.updateBundle();
      if (updateInfo.shouldForceUpdate) {
        await HotUpdater.reload();
      }
    };

    checkUpdate();
  }, []);

  // ... your app
}

HotUpdater.init({
  baseURL: "<your-update-server-url>",
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
});

export default App;

Configuration Reference

HotUpdater.wrap accepts automatic update options.

Common Options

OptionTypeRequiredDescription
baseURLstring | () => string | Promise<string>Yes*Your update server URL (standard approach)
resolverHotUpdaterResolverYes*Custom network operations (advanced)
requestHeadersRecord<string, string>NoCustom HTTP headers for update requests
requestTimeoutnumberNoRequest timeout in milliseconds (default: 5000)
onNotifyAppReady(result) => voidNoCallback invoked after native app-ready state is read

*Either baseURL or resolver must be provided (mutually exclusive)

Automatic Mode Options

The following options are available in automatic mode:

OptionTypeRequiredDescription
updateStrategy"appVersion" | "fingerprint"YesUpdate detection strategy
requestHeadersRecord<string, string>NoCustom HTTP headers for update requests
requestTimeoutnumberNoRequest timeout in milliseconds (default: 5000)
fallbackComponentReact.FC<HotUpdaterFallbackComponentProps>NoUI component shown during updates
onProgress(progress: number) => voidNoCallback fired during bundle download (0-1)
reloadOnForceUpdatebooleanNoAuto-reload on force updates (default: true)
onUpdateProcessCompleted(response) => voidNoCallback when update process completes
onError(error) => voidNoError handler for update failures

fallbackComponent

During an update check, access to the entry point is temporarily blocked while communicating with the server.

  • If the update is force update, the entry point remains blocked, and the progress updates as the bundle downloads.
  • If not force update, the entry point is only blocked during the update check.

Without a fallbackComponent, 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: Optional server message (string | null)

Example:

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text, Modal } from "react-native";

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

export default HotUpdater.wrap({ 
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  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 the automatic HotUpdater.wrap flow receives an update with shouldForceUpdate: true, it prepares the selected transition and reloads the app by default. 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 explicit HotUpdater.reload() call.

This option only controls the automatic HotUpdater.wrap flow. updateBundle() never reloads the app by itself.

The actual reload behavior follows HotUpdater.setReloadBehavior().

Example with auto-reload:

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

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

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  // If you need to send request headers, you can use the `requestHeaders` option.
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
  reloadOnForceUpdate: true, // Automatically reload the app on force updates
})(App);

Example without auto-reload:

import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

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

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  // If you need to send request headers, you can use the `requestHeaders` option.
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
  reloadOnForceUpdate: false, // Keep the current session running
})(App);

onUpdateProcessCompleted

Reports when automatic update handling has finished from the wrapper's perspective.

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

Callback Arguments:

PropertyTypeDescription
status"ROLLBACK" | "UPDATE" | "UP_TO_DATE"The status of the update process
shouldForceUpdatebooleanWhether the update process is forced
idstringThe ID of the bundle to update
messagestring | nullThe optional message of the update process
import { HotUpdater } from "@hot-updater/react-native";
import { View, Text } from "react-native";

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

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion", // or "fingerprint"
  // If you need to send request headers, you can use the `requestHeaders` option.
  requestHeaders: {
    "Authorization": "Bearer <your-access-token>",
  },
  onUpdateProcessCompleted: ({ status, shouldForceUpdate, id, message }) => {
    console.log("Bundle updated:", status, shouldForceUpdate, id, message);
  },

  // If you need to show the progress while downloading the new bundle, you can use the `onProgress` option.
  onProgress: (progress) => {
    console.log("Bundle downloading progress:", progress);
  },
})(App);

onError

Handles all errors during the update process.

Example:

import { HotUpdater } from "@hot-updater/react-native";
import { Alert } from "react-native";

export default HotUpdater.wrap({
  baseURL: "<your-update-server-url>",
  updateStrategy: "appVersion",
  onError: (error) => { 
    // Handle other errors
    console.error("Update error:", error);
  },
})(App);

How It Works

When you use HotUpdater.wrap with automatic updates, it constructs the appropriate endpoint URL based on the updateStrategy:

  • For updateStrategy: "appVersion": GET {baseURL}/app-version/:platform/:appVersion/:channel/:minBundleId/:bundleId
  • For updateStrategy: "fingerprint": GET {baseURL}/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId

The function automatically appends the correct path and parameters to your baseURL.

Advanced: Custom Resolver

For advanced use cases where you need full control over network operations - such as implementing a custom server, using GraphQL, or complex authentication flows - you can use a custom resolver instead of baseURL.

import { HotUpdater } from "@hot-updater/react-native";
import { useEffect } from "react";
import YourApp from "./YourApp";

function App() {
  useEffect(() => {
    const checkUpdate = async () => {
      // When you call HotUpdater.checkForUpdate(),
      // it will use the resolver.checkUpdate() defined below
      const updateInfo = await HotUpdater.checkForUpdate({
        updateStrategy: "appVersion",
      });

      if (updateInfo) {
        await updateInfo.updateBundle();
        if (updateInfo.shouldForceUpdate) {
          await HotUpdater.reload();
        }
      }
    };

    checkUpdate();
  }, []);

  return <YourApp />;
}

export default HotUpdater.wrap({
  resolver: { 
    // Override the default update check logic
    checkUpdate: async (params) => { 
      // Custom network logic - GraphQL, custom API, etc.
      const response = await fetch(`https://custom-api.com/check`, { 
        method: 'POST', 
        body: JSON.stringify({ 
          platform: params.platform, 
          appVersion: params.appVersion, 
          bundleId: params.bundleId, 
        }), 
        headers: params.requestHeaders, 
      }); 
      if (!response.ok) return null; 
      return response.json(); 
    }, 
  }, 
  updateStrategy: "appVersion",
})(App);

Note: The resolver option is mutually exclusive with baseURL. Using resolver.checkUpdate() overrides the default update check implementation.

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: trueHotUpdater.wrap 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