Library / SDK
vantuan88291/react-native-ota-hot-update avatar
vantuan88291/react-native-ota-hot-update

react-native-ota-hot-update: ship a new JavaScript bundle to a live app yourself

React native hot update same as code push, can update using git repository or custom server

694 stars82 forksTypeScriptMIT

At a glance

What is it?
react-native-ota-hot-update is a React Native module that downloads a JavaScript bundle from your own server or a Git repository, installs it after the app restarts, rolls back automatically when the new bundle crashes, and can manage several bundle versions. It suits a team that wants Code Push style OTA updates without a hosted update service, and it does not change native code.
Who is it for?
Adopt react-native-ota-hot-update if you ship a React Native app, want to push JavaScript changes to installed apps without going through the stores, and are prepared to host the bundle and own the versioning. Do not adopt it to deliver native code, since the update path is the JavaScript bundle, and treat the bundle management APIs as preview until they leave the experimental release.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The bundle lives in your server or your Git repository

react-native-ota-hot-update is a React Native module for managing hot updates, in-app updates, with minimal configuration, in the same spirit as Code Push. The distinguishing decision is where the bundle comes from: you control the versioning and host the JavaScript bundle yourself, on your own server or in a Git repository, and the library handles the installation of the update once the bundle has been downloaded.

The stated motivation is that Code Push is retiring soon, and that hosting the bundle yourself gives full control over the update process. The repository carries two separate guides for the two hosting models, DOC_OTA_GIT.md for the Git repository route and DOC_OTA_SERVER.md for the server route, plus OTA_CMS.md and a cms/ directory for a content management piece, and an update.json file at the root.

The key features are the four that a release engineer actually needs. You can host the bundle on your own server or in a Git repository. There is a rollback function. Crash handling covers the case where an incorrect bundle is updated, in which case the library rolls back to the previous bundle version automatically. And there are bundle management features for keeping several versions on the device.

The demos make the two hosting routes concrete, with separate GIF walkthroughs for iOS and Android for the server route, for the Git route, and a third one for bundle management.

One boundary is worth stating at the outset. The unit of delivery is the JavaScript bundle, and the app loads it in place of the bundle that shipped with the build. Native code is not part of that path, so a change to the Android or iOS layer still means a new build and a store release.

Installation is one yarn command and a pod install

The module is installed from npm with yarn, and it ships the native pieces for both platforms:

bash
yarn add react-native-ota-hot-update && yarn add react-native-blob-util

The second package is conditional. The documentation says that if you do not want to manage the download progress, you need to install blob util together, so react-native-blob-util is what the module uses when it downloads the bundle on your behalf.

Autolinking is already handled, and iOS needs the CocoaPods step:

bash
cd ios && pod install

For Expo projects, the module is added through the plugins array in app.json, and the project carries an app.plugin.js at the root for exactly that purpose:

json
"plugins": [
      "react-native-ota-hot-update",
      ...
    ]

The repository also ships a working example app under example/, with its own android, ios, metro.config.js and jest.config.js, and the package scripts wire that up with a workspace command named example. The build tooling uses bob for the library build, release-it for releases, and a separate tsc build for the Expo plugin, with turbo.json and react-native.config.js in the tree.

iOS needs the bundle path replaced in the AppDelegate

The wiring on iOS is a small but non optional change to the app delegate, because the app has to ask the module which bundle to load instead of asking the bundle URL provider.

For a project on the older Objective-C app delegate, the change is in AppDelegate.m, and it keeps the debug path intact:

bash
#import "OtaHotUpdate.h"
...
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  return [OtaHotUpdate getBundle]; ## add this line
#endif
}

From React Native 0.77 the app delegate is a Swift file, so the configuration changes slightly, and the same pattern appears as an override of bundleURL:

bash
import react_native_ota_hot_update
...

override func bundleURL() -> URL? {
        #if DEBUG
            RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
        #else
            OtaHotUpdate.getBundle()  // -> Add this line
        #endif
}

Downloading in the background on iOS is optional and needs extra work in the app delegate, with a UIBackgroundTaskIdentifier property in AppDelegate.h and a begin background task block in the implementation, with a Swift version for React Native 0.77 and above that begins a task named OTAUpdate when the app enters the background and ends it when it returns to the foreground.

Android asks the module for the bundle file path

The Android side mirrors the iOS idea. In MainApplication.kt, the getJSBundleFile override returns the path the module has chosen:

bash
import com.otahotupdate.OtaHotUpdate
...
override fun reactNativeHost: ReactNativeHost =
  object : DefaultReactNativeHost(this) {
    ...
    override fun getJSBundleFile(): String? {
      return OtaHotUpdate.bundleJS(this@MainApplication)
    }
    ...
  }

The Java variant is the same idea in the Java host class, with the getJSBundleFile method returning OtaHotUpdate.getBundleJS(this).

For React Native 0.82 and above the host construction changed again, and the bundle path moves into the reactHost property:

bash
  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 = OtaHotUpdate.bundleJS(applicationContext)
    )
  }

That last point is the recurring theme of the setup, and it is the one to plan for. The hook location moves between React Native versions, so the upgrade of a React Native app in this repository means re-checking this file, which is why the documentation splits it into three separate sections.

Version 2 covers both architectures, version 1 lives on a branch

The architecture story is stated in one short section. New architecture backward compatibility is supported from version 2, and version 2 also supports the old architecture. For the source code of version 1.x.x, the documentation points at a branch called oldArch, and adds that you might need to install version 1.x.x if you are using React Native below 0.70.

So the version choice is tied to the React Native version in a very concrete way, and it is not a soft recommendation. A project on React Native 0.69 or older is on the 1.x line and a different branch of the source, while a project on a current React Native takes the 2.x line with both architectures available.

The release history is recent and busy. The listed releases are 2.4.7 from 2026-08-28, 2.4.6 from 2026-08-26 and 2.4.5 from 2026-08-13, and the package manifest sits at version 2.4.71 with a build pipeline that publishes through release-it. The repository is not archived and the last push was on 2026-10-07.

The licence is MIT, with the author listed as vantuan88291, and the only runtime dependency in the manifest is buffer at ^6.0.3, which tells you the JavaScript side is thin and most of the work happens in the native modules under android/ and ios/.

Bundle management is still a preview release

The bundle management features arrived as a preview release, version 2.4.0-rc.1, and the documentation is explicit that it is experimental and meant for testing.

What the preview adds is a configurable bundle history through the maxBundleVersions setting, so several bundle versions can be kept on the device. There are new APIs, getBundleList(), deleteBundleById() and clearAllBundles(). Bundles are identified with descriptive folder names carrying the version and a timestamp, and older bundles are removed automatically once the limit is exceeded.

The discussion for the feature is in PR #132, and the work sits on a branch called task/manage_bundle. Installing the preview is a matter of pinning the exact version:

bash
yarn add [email protected]

The distinction between the stable line and the preview is worth keeping clear, because the stable releases are where the crash rollback and the two hosting routes are the tested path, while the history and cleanup behaviour is the newer surface. A team that wants rollback today and bundle management later can take the stable release and revisit the choice when the preview settles.

The rest of the repository shows the same split in code, with an update.json file at the root for the update metadata, a plugin/ directory for the Expo plugin, and the platform folders shipped in the published package alongside the podspec and react-native.config.js.

How this compares with Code Push and with Expo updates

The obvious comparison is Code Push, which the project positions itself against. The difference in approach is where the update pipeline lives. Code Push is a hosted service that takes your build, stores it, and serves it to clients on its own terms. This library keeps the bundle in your infrastructure, whether that is a server you operate or a Git repository, and the repository provides the two guides, DOC_OTA_SERVER.md and DOC_OTA_GIT.md, that walk through each route.

What you give up by moving the pipeline in house is the service. The project compensates with pieces that a hosted service would otherwise provide: the crash handling that rolls back to the previous bundle when an incorrect update crashes the app, the explicit rollback function for a case where the app does not crash but the behaviour is wrong, and the bundle management APIs for controlling what is stored on the device.

The second comparison is Expo updates, which matters because the project supports Expo through the plugins entry in app.json. In an Expo project the app plugin only wires the module into the build configuration, so the bundle hosting and the update check are still yours. That is a different arrangement from an Expo managed workflow where the update service is part of the platform, and it is the arrangement the two separate hosting guides describe.

Editorial conclusion

Adopt react-native-ota-hot-update if you ship a React Native app, want to push JavaScript changes to installed apps without going through the stores, and are prepared to host the bundle and own the versioning. Do not adopt it to deliver native code, since the update path is the JavaScript bundle, and treat the bundle management APIs as preview until they leave the experimental release. Verify first which React Native version your project runs, because the wiring differs for versions 0.70 and below, 0.77 and above and 0.82 and above, and that react-native-blob-util is installed if you want the library to handle the download progress for you.

Frequently asked questions

How do I install react-native-ota-hot-update?

Run yarn add react-native-ota-hot-update && yarn add react-native-blob-util, where the second package is needed if you do not want to manage the download progress yourself. Autolinking is already handled, and on iOS you then run cd ios && pod install.

Which React Native versions does react-native-ota-hot-update support?

Version 2 supports the new architecture with backward compatibility to the old architecture. The source for version 1.x.x lives on the oldArch branch, and you may need version 1.x.x if you are on React Native below 0.70.

How does the rollback work in react-native-ota-hot-update?

Crash handling covers the case where an incorrect bundle is updated: the library catches the crash exception and automatically rolls back to the previous bundle version. There is also a rollback function for cases where the update does not crash the app.

Can react-native-ota-hot-update deliver native code changes?

No. The unit it installs is the JavaScript bundle, downloaded from your server or your Git repository, and the native side is part of the app build shipped through the stores. The plugin/ folder and the podspec cover the native code of the module itself, not of your app.

Is the bundle management feature in react-native-ota-hot-update stable?

Not yet. It was introduced as a preview release, version 2.4.0-rc.1, described as experimental and for testing, with the discussion in PR #132 and the work on the task/manage_bundle branch. The listed stable releases are 2.4.7, 2.4.6 and 2.4.5.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. vantuan88291/react-native-ota-hot-update on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/vantuan88291-react-native-ota-hot-update.svg)](https://hysenlabs.com/projects/vantuan88291-react-native-ota-hot-update)

Was this useful?