# How does it work? (https://hot-updater.dev/docs/concepts/how-it-works) > Understanding the core infrastructure and update decision logic ## Core Infrastructure `hot-updater` consists of three key components: - **Storage**: A place where JavaScript bundles are stored, supporting AWS S3, Cloudflare R2, Supabase Storage, Firebase Storage, etc. - **Database**: Stores metadata about deployed bundles (version information, etc.) and manages update information. - **Server**: Determines whether updates are required based on the app's current state, operating through AWS Lambda@Edge, Cloudflare Workers, Supabase Edge Functions, or Firebase Cloud Functions. Storage and Database are configured using plugins defined in `hot-updater.config.ts`. The Server is initialized and deployed using the `hot-updater init` command. ## Update Decision Logic `hot-updater` primarily uses UUIDv7 for its operations, with the following update determination process: ### 1. Bundle ID Generation and Management - Running `hot-updater deploy` invokes the selected build plugin, which generates a UUIDv7-formatted Bundle ID during bundling. - This Bundle ID includes the deployment timestamp and is uniquely generated per bundle. ### 2. Initial Native App Build - The first version of the native app does not have an initial Bundle ID, as it isn't created by `hot-updater deploy` but by the native build process. - In this case, a minimal Bundle ID (`minBundleId`) in UUIDv7 format, based on the app build timestamp, is used. ### 3. Communication with the Update Server - The app communicates with the server using the current Bundle ID to verify if the bundle is activated (`enabled=true`). - If the bundle isn't active, the app forcibly updates (rollbacks) to a previously active bundle. - If an active bundle newer than the current app version exists, the app updates to the latest available bundle. ### 4. Usage of minBundleId - The `minBundleId` is determined based on the native app's build timestamp. - The existence of a native app build ensures the embedded bundle is the latest at that point. Bundles older than the `minBundleId` are ignored. - Every new deployment generates a new Bundle ID, ensuring accurate and reliable updates. # Plugin System (https://hot-updater.dev/docs/concepts/plugin-system) > Hot Updater uses a flexible plugin system that lets you customize how bundles are built, stored, and managed to fit your infrastructure. ## Build Plugin Build plugins handle the bundling process when you run the `hot-updater deploy` command. They generate the JavaScript bundles for your updates. ### Supported Plugins - **`@hot-updater/bare`**: Runs the project's configured bundler through React Native CLI's `bundle` command. - **`@hot-updater/rock`**: Runs the project's configured bundler through the `bundle` command in [Rock](https://github.com/callstack/rock) CLI (formerly RNEF). - **`@hot-updater/expo`**: Executes the bundle command through Expo. ## Storage Plugin Storage plugins upload your generated bundles during the `hot-updater deploy` command and store them in your chosen storage provider. Storage plugins expose explicit environment profiles: - `node`: deploy-time APIs for upload, delete, and local file downloads. - `runtime`: update-check APIs for HTTP(S) download URLs and small metadata reads. `hot-updater.config.ts` uses the `node` profile. `createHotUpdater` uses the `runtime` profile. Most apps can use the official storage plugins directly; custom plugin authors only need the profile details when implementing their own storage provider. ### Supported Plugins - **`@hot-updater/supabase`**: Provides `supabaseStorage` functionality, leveraging Supabase for storage. - **`@hot-updater/cloudflare`**: Provides deploy-time `r2Storage` and Worker runtime storage for Cloudflare R2. - **`@hot-updater/aws`**: Provides `s3Storage` functionality, enabling the use of AWS S3 for storage. - **`@hot-updater/firebase`**: Provides `firebaseStorage` functionality, utilizing Firebase Storage for storing update bundles. ## Database Plugin Database plugins store bundle metadata that your app uses to check for updates. They run during the `hot-updater deploy` command. ### Supported Plugins - **`@hot-updater/supabase`**: Provides `supabaseDatabase` functionality, using Supabase as a database solution. - **`@hot-updater/aws`**: Provides `s3Database` functionality, utilizing AWS for database storage. - **`@hot-updater/cloudflare`**: Provides `d1Database` functionality, leveraging Cloudflare D1 for database storage. - **`@hot-updater/firebase`**: Provides `firebaseDatabase` functionality, using Firebase Firestore for storing update metadata. # Automatic Rollback (https://hot-updater.dev/docs/concepts/automatic-rollback) > Hot Updater verifies newly installed bundles on first launch and automatically recovers to a working bundle if startup fails. ## What is Automatic Rollback? Automatic rollback is the safety mechanism that prevents a bad OTA bundle from trapping users in a crash loop. When a new bundle is installed, Hot Updater does not trust it immediately. It launches that bundle in a temporary state first, keeps the last known-good bundle as a fallback, and only treats the new bundle as safe after startup succeeds. This happens automatically when you use `HotUpdater.wrap()`. For custom manual flows without a root wrapper, call [`HotUpdater.init()`](/docs/react-native-api/init) when your runtime considers the app ready. ## Core Mechanism Hot Updater manages two roles during rollout: - **Staging bundle**: the newly installed bundle waiting to be verified - **Stable bundle**: the last bundle that was already known to start successfully The flow is: 1. **Install the update** - The downloaded bundle becomes the new staging bundle. - The previously working bundle is kept as the fallback, if one exists. 2. **Launch the staging bundle** - On the next app start, Hot Updater loads the staging bundle first. 3. **Verify startup** - If the app reaches its first successful render, the launch is treated as successful. - The staging bundle becomes the current trusted bundle. 4. **Recover on failure** - If the app exits or crashes before that point, the staging bundle is treated as failed. - On the next launch, Hot Updater automatically returns to the last stable bundle. ## What Counts as a Failed Launch? A bundle is considered failed if it cannot complete startup. In practice, that means the app never reaches the point where Hot Updater can confirm that the new bundle started successfully. Typical examples include: - a JavaScript error during startup - a native crash while the new bundle is loading - a fatal error before the first screen appears This is why Hot Updater must be configured with `HotUpdater.wrap()` or `HotUpdater.init()` for rollback support. These APIs connect bundle verification to the app lifecycle. ## What Happens During Rollback? When rollback happens, Hot Updater: - stops using the failed staging bundle - restores the previous stable bundle when one exists - falls back to the embedded bundle when there is no stable OTA fallback - records the failed bundle in crash history This lets users reopen the app normally instead of hitting the same startup failure again. ## Managing Crashed Bundles Hot Updater keeps a crash history for bundles that failed startup and triggered recovery. ### getCrashHistory() Returns the bundle IDs that were marked as failed and rolled back. ```tsx import { HotUpdater } from "@hot-updater/react-native"; function checkCrashedBundles() { const crashedBundles = HotUpdater.getCrashHistory(); if (crashedBundles.length > 0) { console.log("Crashed bundles:", crashedBundles); // Send to your monitoring service } } ``` You can use this to: - monitor deployment health - identify which bundle IDs failed in production - send rollback events to analytics or error tracking tools ### clearCrashHistory() Clears the crash history so a previously failed bundle ID can be retried again. ```tsx import { HotUpdater } from "@hot-updater/react-native"; async function retryFailedBundle() { HotUpdater.clearCrashHistory(); console.log("Crash history cleared"); } ``` Only clear crash history after fixing the underlying issue. Otherwise the same broken bundle can be applied again. ### Crash History Blocking When a bundle fails startup, Hot Updater adds that exact bundle ID to crash history and blocks it from being applied again. This prevents repeated crash loops from the same broken deployment. To deploy a fixed version: 1. Fix the bug in your code 2. Deploy again with a new bundle ID 3. The new bundle ID bypasses the crash history If you need to retry the same bundle ID: 1. Verify the bundle is fixed 2. Call `clearCrashHistory()` to reset the blocked list 3. Redeploy the bundle ## In One Sentence Hot Updater only trusts a new bundle after it launches successfully once. Until then, it keeps a working fallback and can automatically recover if startup fails. # Introduction (https://hot-updater.dev/docs/get-started/introduction) > Self-hostable OTA update solution for React Native apps, alternative to CodePush.