HotupdaterHot Updater
Deliver updates

Deploy

Deploy an update to one platform or both platforms sequentially.

Publish an update

Deploy builds and uploads the update files for each platform and publishes its delivery policy. Each platform gets one ID, shared by the deployment output, the console, and hotUpdater.getBundleId().

Checklist

  1. Complete manual setup or agent setup, including the server and client key.
  2. Connect the app with HotUpdater.init and implement the custom update flow, then apply the native integration.
  3. Install a release build with the intended channel and compatibility target.

For your first deployment, follow Test an OTA update to verify delivery in a test channel before using the commands below.

Options

Options:
  -p, --platform <platform>                    specify the platform (choices: "ios", "android")
  -t, --target-app-version <targetAppVersion>  specify the target app version (semver format e.g. 1.0.0, 1.x.x)
  -d, --disabled                               create the bundle disabled (default: false)
  -f, --force-update                           force update the app (default: false)
  -o, --bundle-output-path <bundleOutputPath>  the directory where bundle archives will be generated
  -r, --rollout <percentage>                   specify the rollout percentage for the new bundle (0-100) (default: 100)
  -i, --interactive                            interactive mode (default: false)
  -c, --channel <channel>                      specify the channel to deploy (default: "production")
  -m, --message <message>                      Specify a custom message for this deployment. If not provided, the latest git commit message will be used as the deployment message
  -h, --help                                   display help for command

Usage

Deploy Both Platforms

Deploy each platform explicitly. To deploy iOS first and Android only after it succeeds, run:

npx hot-updater deploy -p ios -o .hot-updater/output/deploy/ios &&
  npx hot-updater deploy -p android -o .hot-updater/output/deploy/android

Each command commits independently. If Android fails, the successful iOS update remains published. Keep the channel, rollout, and other delivery options consistent across both commands when they should share the same policy.

Omitting -p deploys both platforms in one command. It builds and uploads each platform, then commits both in one database transaction, so neither is published unless both succeed.

That command loads hot-updater.config.ts once for both platforms. A config object gives them the same database and storage. A config that exports a function runs it once for each platform, so create its adapters outside the function and return the same ones. Otherwise deploy stops before it builds, with Deploying multiple platforms requires a shared database configuration. or Deploying multiple platforms requires a shared storage configuration.

hot-updater.config.ts (excerpt)
// Created once, outside the function, so both platforms get the same adapters.
const storage = s3Storage({ /* ... */ });
const database = standaloneRepository({ /* ... */ });

// options is { platform, channel }, or null for a command without a platform.
export default defineConfig((options) => ({
  build: bare({ enableHermes: true }),
  storage,
  database,
  plugins: [insights(), apiKeys()],
  // ... settings that depend on options?.platform or options?.channel
}));

With -p, the archive is written directly to <bundle-output-path>/bundle.tar.br. The commands above therefore produce .hot-updater/output/deploy/ios/bundle.tar.br and .hot-updater/output/deploy/android/bundle.tar.br. Without -p, each platform's archive is written to <bundle-output-path>/<platform>/bundle.tar.br. The manifest and unarchived files remain in the build adapter's output directory, which is configured separately.

Deployment Result

After its database commit succeeds, each single-platform deploy prints its public Bundle ID:

Deployment successful
    ID: 01a0586e-a286-7a74-a959-6d2c770b8793

Record the ID from each platform's command.

Interactive deploy opens that exact update in the console. Use this ID with bundle show, bundle update, bundle disable, bundle delete, or bundle promote. The advanced patch command takes the Artifact ID shown in Advanced diagnostics.

Bundle Diffing

New deployments upload a manifest and its per-file artifacts. The runtime reuses matching files from the current OTA or built-in app and downloads only the remaining files. No deploy flag is required for this behavior.

Hermes binary patch generation is enabled by default (patch.enabled: true). Deploy therefore also tries to prepare compatible bsdiff patches. Set patch.enabled: false only when you want to disable this optimization. Patch generation is best-effort; a skipped patch does not fail the deployment because the complete Hermes file remains available.

See Bundle Diffing for the runtime behavior and fallback rules.

Interactive Mode

Use interactive mode to choose deployment options with the keyboard:

npx hot-updater deploy -i

The -i (or --interactive) flag enables interactive keyboard input.

For Continuous Deployment (CD) Pipelines

Use -p to scope each CI job or step to exactly one platform:

npx hot-updater deploy -p ios

Use -p android for Android, or the explicit sequence above when one job deploys both platforms.

Force Update

Mark a Bundle as requiring immediate application when selected. A custom update flow receives shouldForceUpdate: true and controls when to reload after a successful download.

Run the following command:

npx hot-updater deploy -p <"ios" | "android"> -f

The -f (or --force-update) flag sets delivery behavior on the new Bundle. It does not rewrite the uploaded artifact.

A forced Bundle stays required for devices that skip it. A device running an older bundle that updates straight to a newer, non-forced Bundle still receives shouldForceUpdate: true, as long as its cohort was eligible for the forced one. Devices that already run the forced Bundle get later updates as deployed.

Channel

The -c (or --channel) flag specifies the release channel.

Run the following command:

npx hot-updater deploy -p <"ios" | "android"> -c "<channel>"

The -c (or --channel) default is production.

For more details about default channels, refer to Default Channel Setup.

Rollout

The -r (or --rollout) flag sets the rollout percentage for the new Bundle.

Run the following command:

npx hot-updater deploy -p <"ios" | "android"> -r 25

Use whole percentages from 1 to 99 for gradual rollout, 100 for a full rollout, and 0 when you want to create the Bundle without exposing it to numeric rollout until you edit the same Bundle later.

Hot Updater maps rollout percentages to 1..1000 numeric cohorts internally. For example, -r 25 means 250 of 1000 numeric cohorts are eligible for that Bundle. Numeric cohort selection is seeded by its ID and remains stable when that Bundle's rollout policy changes.

If you omit -r, the default value is 100, so the new Bundle is eligible for all numeric and valid custom cohorts immediately.

For more on gradual rollout, current device cohorts, and cohort targeting from the console, see Rollout & Cohorts.

Message

The -m (or --message) flag specifies the new Bundle's public message.

Run the following command:

npx hot-updater deploy -p <"ios" | "android"> -m "<message>"

Pass the same -m value to each platform command when both updates should share a message.

Force Update Flag Difference

Update TypeApplication in a custom flowHow to Enable
DefaultDownload, then reload at a safe point or apply on the next app start.Default setting
Force UpdateRead shouldForceUpdate: true and choose a reload point after download succeeds.Use the --force-update flag or console.

In the custom flow, shouldForceUpdate is a signal for your application to call reload() after a successful download. Your code controls the restart; setting the server flag alone does not restart the app.

On this page