Basic Usage
This guide walks you through the essential steps to integrate hot-updater into your React Native project.
Provider Setup
Before configuring the build plugin, you need to set up a provider to handle updates. Hot-updater supports multiple managed providers that handle storage and update distribution.
Step 1: Install hot-updater
First, install the hot-updater package:
npm install hot-updater --save-devStep 2: Initialize Your Provider
Run the initialization command to set up your provider interactively:
npx hot-updater initThis interactive CLI will guide you through:
-
Build Plugin Selection: Choose your build system (Bare/React Native CLI, Re.Pack, or Expo)
-
Provider Selection: Select from available providers:
-
Provider Configuration: Follow provider-specific prompts for authentication and resource setup.
Step 3: Generated Configuration
After initialization, two files will be generated:
.env.hotupdater - Contains provider credentials and configuration:
# Example for Supabase
HOT_UPDATER_SUPABASE_URL=https://your-project.supabase.co
HOT_UPDATER_SUPABASE_ANON_KEY=your-anon-key
HOT_UPDATER_SUPABASE_BUCKET_NAME=your-bucket-namehot-updater.config.ts - Contains provider integration settings:
import { bare } from "@hot-updater/bare";
import { supabaseStorage, supabaseDatabase } from "@hot-updater/supabase";
import { defineConfig } from "hot-updater";
import { config } from "dotenv";
config({ path: ".env.hotupdater" });
export default defineConfig({
build: bare({ enableHermes: true }),
storage: supabaseStorage({
supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
supabaseAnonKey: process.env.HOT_UPDATER_SUPABASE_ANON_KEY!,
bucketName: process.env.HOT_UPDATER_SUPABASE_BUCKET_NAME!,
}),
database: supabaseDatabase({
supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
supabaseAnonKey: process.env.HOT_UPDATER_SUPABASE_ANON_KEY!,
}),
});For detailed provider-specific setup instructions, see the Self-Hosting (Managed) documentation.
The environment variables in .env are used only during deployment, not in your app bundle. However, if you're using react-native-dotenv, review the Security guidelines.
Step 4: Wrap Your Application
Add the HotUpdater wrapper to your main application component:
import { HotUpdater, getUpdateSource } from "@hot-updater/react-native";
function App() {
return (
<View>
<Text>Hello World</Text>
</View>
);
}
export default HotUpdater.wrap({
source: getUpdateSource("https://your-update-server-url/api/check-update", {
updateStrategy: "appVersion", // or "fingerprint"
}),
requestHeaders: {
// Optional: Add custom headers if needed
},
fallbackComponent: ({ progress, status }) => (
<View
style={{
flex: 1,
padding: 20,
borderRadius: 10,
justifyContent: "center",
alignItems: "center",
backgroundColor: "rgba(0, 0, 0, 0.5)",
}}
>
<Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
{status === "UPDATING" ? "Updating..." : "Checking for Update..."}
</Text>
{progress > 0 ? (
<Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
{Math.round(progress * 100)}%
</Text>
) : null}
</View>
),
})(App);The update server URL will be provided after running npx hot-updater init. Check your terminal output or provider console for the correct URL.
Plugin Configuration
Configure the build plugin to set the bundle ID at build time. This is necessary for integrating the hot-updater plugin into your project.
Add the following to your babel.config.js file:
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: [
'hot-updater/babel-plugin',
],
};First, install the Re.Pack plugin:
npm install @hot-updater/repack --save-devThen add the following to your rspack.config.mjs file:
import { HotUpdaterPlugin } from "@hot-updater/repack";
export default {
// ...
plugins: [
new Repack.RepackPlugin(),
new HotUpdaterPlugin()
],
};Add the plugin to your app.json file as shown below:
{
"expo": {
"plugins": [
[
"@hot-updater/react-native",
{
"channel": "production"
}
]
]
}
}Run prebuild to apply the changes:
npx expo prebuildRun the following command to customize your Babel configuration:
npx expo customize babel.config.jsAdd the following to your babel.config.js file:
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: [
'hot-updater/babel-plugin',
],
};For Expo projects, the plugin automatically generates the native code configuration described in the next section.
Native Code Setup
To complete the integration of hot-updater, you'll need to add native code modifications for both Android and iOS platforms. This step ensures the hot-updater can interact with your app's underlying framework to apply updates seamlessly.
If you're using Expo with the plugin configured above, this step is handled automatically during prebuild.
Android
For React Native 0.82 and above, modify your MainApplication.kt:
package com.hotupdaterexample
import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.hotupdater.HotUpdater
class MainApplication : Application(), ReactApplication {
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
context = applicationContext,
packageList =
PackageList(this).packages.apply {
// Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage())
},
jsBundleFilePath = HotUpdater.getJSBundleFile(applicationContext),
)
}
override fun onCreate() {
super.onCreate()
loadReactNative(this)
}
}For React Native versions below 0.82, modify your MainApplication.kt:
package com.hotupdaterexample
import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
import com.hotupdater.HotUpdater
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
// Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage())
}
override fun getJSMainModuleName(): String = "index"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
override fun getJSBundleFile(): String? {
return HotUpdater.getJSBundleFile(applicationContext)
}
}
override val reactHost: ReactHost
get() = getDefaultReactHost(applicationContext, reactNativeHost)
override fun onCreate() {
super.onCreate()
SoLoader.init(this, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
}
}For Java-based projects, modify your MainApplication.java:
package com.hotupdaterexample;
import android.app.Application;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import java.util.List;
import com.hotupdater.HotUpdater;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new DefaultReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@Override
protected String getJSBundleFile() {
return HotUpdater.Companion.getJSBundleFile(this.getApplication().getApplicationContext());
}
@Override
protected boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}
@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
DefaultNewArchitectureEntryPoint.load();
}
ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
}iOS
For Swift projects, modify your AppDelegate.swift:
import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import HotUpdater
@main
class AppDelegate: RCTAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
self.moduleName = "HotUpdaterExample"
self.dependencyProvider = RCTAppDependencyProvider()
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = [:]
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func sourceURL(for bridge: RCTBridge) -> URL? {
self.bundleURL()
}
override func bundleURL() -> URL? {
#if DEBUG
RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
Bundle.main.url(forResource: "main", withExtension: "jsbundle")
HotUpdater.bundleURL()
#endif
}
}For Objective-C projects, modify your AppDelegate.mm:
#import "AppDelegate.h"
#import <HotUpdater/HotUpdater.h>
#import <React/RCTBundleURLProvider.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"HotUpdaterExample";
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self bundleURL];
}
- (NSURL *)bundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
return [HotUpdater bundleURL];
#endif
}
@endNext Steps
Now that you've completed the setup, you can start deploying updates:
Deploy Your First Update
Build and publish an update to your users:
npx hot-updater deployUse the interactive mode for guided deployment:
npx hot-updater deploy -iFor emergency updates with forced reload:
npx hot-updater deploy -i -fMonitor and Manage Updates
Open the console to track deployments, manage versions, and perform rollbacks:
npx hot-updater consoleExplore Advanced Features
Learn more about advanced capabilities:
- Update Strategies - Choose between app version and fingerprint strategies
- Channel Management - Manage multiple environments and user groups
- Simulator Testing - Test updates in release mode before production
- Security Best Practices - Secure your update infrastructure