AWS S3 Storage + Lambda@Edge Function
This guide walks you through setting up hot-updater with AWS S3 Storage and Lambda@Edge Function in a React Native project. You'll configure the environment, install required packages, and initialize AWS for seamless updates.
Prerequisites
Before you begin, make sure the following are ready:
- Node.js: Version 20 or later is recommended.
 
- AWS Account: Sign up at AWS if you don't have one.
 
- AWS CLI: Install the AWS CLI and configure your credentials.
 
Required AWS Permissions
Hot Updater requires specific AWS IAM permissions for setup and ongoing usage:
1. Initialization (One-Time Setup)
Used for hot-updater init:
AmazonS3FullAccess: Create and read S3 buckets. 
AWSLambda_FullAccess: Create and update Lambda functions. 
CloudFrontFullAccess: Manage CloudFront distributions. 
IAMFullAccess: Create IAM roles for Lambda@Edge. 
SSMFullAccess: Create Access to SSM Parameters for storing CloudFront key pairs. 
2. Ongoing Usage
Used for hot-updater deploy and hot-updater console:
AmazonS3FullAccess: Manage bundles and metadata in the S3 bucket. 
For ongoing usage, create a separate access token with limited permissions.
Step 1: Install Required Packages
Run the following command to install dependencies:
npm install hot-updater --save-dev
 
Step 2: Configure AWS
Run the initialization script to start the interactive setup process. Use the following command with your preferred package manager:
Interactive Setup Steps
- Select a Build Plugin: Choose a build plugin for your project (e.g., Bare (React Native CLI) for React Native).
 
- Select a Provider: Select AWS + Lambda@Edge as the provider for handling updates.
During the setup, you will be prompted to:
 
- Choose AWS Login Method: Select between AWS Access Key or SSO login
 
- Enter AWS Credentials: Input your AWS credentials with required permissions
 
- Select Region: Choose an AWS region for your S3 bucket
 
- Select S3 Bucket: Choose an existing bucket or create a new one
 
- Create IAM Role: Create or select an IAM role for Lambda@Edge
 
- Deploy Lambda Function: Deploy the Lambda@Edge function to handle updates
 
- Create/Update CloudFront Distribution: Create or update a CloudFront distribution
 
 
Once the setup is complete, a .env file will be generated containing the following keys:
# This key was generated via SSO login and may expire. Update it with an S3FullAccess and CloudFrontFullAccess key.
HOT_UPDATER_S3_ACCESS_KEY_ID=your-access-key-id
# This key was generated via SSO login and may expire. Update it with an S3FullAccess and CloudFrontFullAccess key.
HOT_UPDATER_S3_SECRET_ACCESS_KEY=your-secret-access-key
HOT_UPDATER_S3_BUCKET_NAME=your-s3-bucket-name
HOT_UPDATER_S3_REGION=your-region
 
WARNING
If you’re not using the react-native-dotenv solution, the tokens from your .env file will not be included in your app bundle and are therefore not exposed to risks. However, if you’re still concerned,
please refer to the article below for more details:
Security 
Step 3: Generated Configurations
During the initialization process, the following file is automatically generated:
hot-updater.config.ts: This file contains the configuration settings for integrating AWS with your project. 
hot-updater.config.ts
import { bare } from "@hot-updater/bare";
import { s3Storage, s3Database } from "@hot-updater/aws";
import { defineConfig } from "hot-updater";
import "dotenv/config";
const commonOptions = {
  bucketName: process.env.HOT_UPDATER_S3_BUCKET_NAME!,
  region: process.env.HOT_UPDATER_S3_REGION!,
  credentials: {
    accessKeyId: process.env.HOT_UPDATER_S3_ACCESS_KEY_ID!,
    secretAccessKey: process.env.HOT_UPDATER_S3_SECRET_ACCESS_KEY!,
  },
};
export default defineConfig({
  build: bare({ enableHermes: true }),
  storage: s3Storage(commonOptions),
  database: s3Database({
    ...commonOptions,
    cloudfrontDistributionId: process.env.HOT_UPDATER_CLOUDFRONT_DISTRIBUTION_ID!,
  }),
});
 
Step 4: Change.env file (Optional)
By this point, the .env file should already be created. The token inside was generated when you ran the hot-updater init command.
The token may have excessive permissions due to infrastructure setup or expire if SSO was used.
To avoid issues, update it with a permanent token with S3FullAccess and CloudFrontFullAccess.
.env
HOT_UPDATER_S3_ACCESS_KEY_ID=your-access-key-id
HOT_UPDATER_S3_SECRET_ACCESS_KEY=your-secret-access-key
 
Step 5: Add HotUpdater to Your Project
The HotUpdater component wraps your application, enabling seamless delivery of updates and fallback UI during updates. Follow these steps to integrate it into your App.tsx:
App.tsx
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-cloudfront-distribution-url>/api/check-update", { 
    updateStrategy: "appVersion", // or "fingerprint"
  }),
  requestHeaders: {
    // if you want to use the request headers, you can add them here
  },
  fallbackComponent: ({ progress, status }) => (
    <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>
      {progress > 0 ? (
        <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
          {Math.round(progress * 100)}%
        </Text>
      ) : null}
    </View>
  ),
})(App);
 
Step 6: Add Babel / Re.Pack / Expo Plugin to Your Project
In this step, you will configure Babel 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:
babel.config.js
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    'hot-updater/babel-plugin',
  ],
};
 
Step 7: Add Native Code
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.
Android
android/app/src/main/java/com/<your-app-name>/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)
}
}
 
iOS
ios/<your-app-name>/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
  }
}
 
Verifying the Setup
- Check your AWS dashboard for the newly created bucket, Lambda@Edge function, and CloudFront distribution.
 
- Test the HotUpdater integration in your React Native app.
 
You're all set! 🎉 Start using hot-updater with AWS for seamless updates in your React Native app.
This document simplifies the initialization process, making it easy for developers to get started with minimal friction.