HotupdaterHot Updater
Self Hosting (Managed)

AWS Provider

Deploy Hot Updater on AWS with DynamoDB, S3, CloudFront, and Lambda@Edge, then connect your app.

Overview

Use this preset to provision an OTA server on AWS. For a new app, start with Choose infrastructure. Provision the provider resources here, then connect your app with the verified URL and key.

Prerequisites

You need the following resources and access. An AI agent can prepare missing resources through its available provider tools.

  • Node.js: The CLI requires 20.19+. Agent setup uses a client-key helper that requires Node 22.18+ or Node 24+; prepare it before provisioning resources.
  • AWS Account: Sign up at AWS if you don't have one.
  • AWS CLI (terminal setup): Install the AWS CLI and sign in or configure a profile.

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.
  • AmazonDynamoDBFullAccess_v2: Create and configure the metadata table.
  • AWSLambda_FullAccess: Create and update Lambda functions.
  • CloudFrontFullAccess: Manage CloudFront distributions.
  • IAMFullAccess: Create IAM roles for Lambda@Edge.
  • AmazonSSMFullAccess: Access SSM Parameters used for CloudFront key pairs.

2. Ongoing usage

Used for hot-updater deploy and hot-updater console:

  • AmazonS3FullAccess: Manage bundle artifacts in the S3 bucket.
  • DynamoDB table access for metadata queries and writes.
  • cloudfront:CreateInvalidation: Invalidate CloudFront cache after deployments.

For ongoing usage, create a separate access token with limited permissions. Here's a minimal policy example for CloudFront invalidation:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["cloudfront:CreateInvalidation"],
      "Resource": "arn:aws:cloudfront::<ACCOUNT_ID>:distribution/<DISTRIBUTION_ID>"
    }
  ]
}

If this permission is missing, you may encounter the following error:

AccessDenied: User: arn:aws:sts::***:assumed-role/***/*** is not authorized to perform: cloudfront:CreateInvalidation on resource: arn:aws:cloudfront::***:distribution/*** because no identity-based policy allows the cloudfront:CreateInvalidation action

Step 1: Install required packages

Complete Install packages in the React Native project before running init or an agent scaffold. Install the CLI, React Native SDK, and the build adapter that matches your app, then install this provider:

npm install @hot-updater/aws --save-dev

An agent can perform these steps after inspecting the app's package manager and build configuration.

Step 2: Configure AWS

Choose how to set up AWS:

Install the Hot Updater skill, then ask your coding agent:

$hot-updater Set up infrastructure on AWS for this project.

The agent inspects your app, discovers existing configuration and resources, and asks only for missing choices or access. It uses hot-updater agent infra setup to generate the deployment templates, then applies and verifies them with available provider tools. If authentication is needed, sign in through the provider or save credentials in a local ignored file; do not paste secrets into the conversation. See Agent Infrastructure for setup and resume.

After setup, review the local configuration. Interactive init writes the settings below to .env.hotupdater; an agent merges the needed settings into your project. Resource selections and the authentication mode are persisted for deterministic reruns. AWS credentials are included only for account/access-key mode and only when you consent to storing them.

HOT_UPDATER_DYNAMODB_TABLE_NAME=hot-updater-v1
HOT_UPDATER_AWS_AUTH_MODE=local-session
HOT_UPDATER_AWS_LAMBDA_NAME=hot-updater-v1-edge
HOT_UPDATER_S3_BUCKET_NAME=your-s3-bucket-name
HOT_UPDATER_S3_REGION=your-region
HOT_UPDATER_CLOUDFRONT_DISTRIBUTION_ID=your-distribution-id
HOT_UPDATER_API_KEY=your-api-key

Managed init reuses HOT_UPDATER_API_KEY when supplied or creates an API key, registers it in DynamoDB, and persists the plaintext value locally. Send this API key in the app's x-api-key request header. It does not authorize management or Insights-query routes. To list, add, or revoke keys later, run hot-updater api-key from the app directory.

If you choose a shared AWS profile or SSO, the generated env file also includes:

HOT_UPDATER_AWS_PROFILE=your-profile-name

If you choose the current AWS CLI/default session mode, no extra credential env variables are written. The generated config uses the AWS SDK default provider chain directly.

If you choose account/access-key mode and consent to persistence, the generated env file also includes:

# The generated key may be over-privileged or temporary depending on how you authenticated during init.
HOT_UPDATER_S3_ACCESS_KEY_ID=your-access-key-id
HOT_UPDATER_S3_SECRET_ACCESS_KEY=your-secret-access-key

Keep provider credentials from .env.hotupdater in the CLI, CI, or server environment. Configure the update server URL and client API key explicitly in the app as shown below. Treat both as extractable from the app bundle; never include provider credentials.

See Security.

Optional: Bundle signing

Managed AWS init does not create or enable a signing key. The built-in local config works without a signing adapter. For non-exportable key custody, use the AWS KMS signer from hot-updater/signing; signing is independent of storage and database choice. Embed the chosen public key in a native release before deploying signed bundles. Signing credentials belong in the deploy environment, never in the React Native app.

Step 3: Add HotUpdater to your project

After provisioning, record these outputs for Set up your app:

OutputValue
Client base URLhttps://<your-cloudfront-distribution-url>
Client request headerx-api-key
Client API keyThe saved HOT_UPDATER_API_KEY in your ignored .env.hotupdater
Deploy configurationhot-updater.config.ts and the selected provider resources

Use the actual URL returned by deployment. Configure the SDK and native bundle loader through Set up your app, using the selected build adapter and the same update strategy as hot-updater.config.ts. Only the client API key belongs in the mobile app's build-time configuration; provider credentials stay in the deploy environment.

The managed AWS runtime exposes /version publicly. OTA update checks, Insights ingestion, and Remote Config fetches require x-api-key: $HOT_UPDATER_API_KEY, using a key registered or created during init. Internally, the server runs the insights(), apiKeys(), and remoteConfig() plugins; only handlers.client is mounted. API keys do not authorize Insights query routes, and bundle management endpoints are not mounted on the public function URL.

Generated configuration and operations

Init generates hot-updater.config.ts with your AWS storage and database, and plugins: the server plugins the managed Lambda@Edge function runs, apiKeys(), insights(), and remoteConfig(), imported from hot-updater/plugins. The CLI and the Console reach S3 and DynamoDB through these settings and run the same plugins as the function. The managed function runs these official plugins only; to run other server plugins, use a custom server.

On a rerun, init updates storage, database, and plugins in the existing file and keeps your other settings, including a wrapped build such as withSentry(bare()). When it cannot edit hot-updater.config.ts, such as a config that a function returns, it leaves the file unchanged and prints the storage, database, and plugins lines to add.

If you choose current AWS CLI/default session, the generated config uses the AWS SDK default provider chain instead of embedding access keys:

hot-updater.config.ts
import { dynamoDB, s3Storage } from "@hot-updater/aws";
import { apiKeys, insights, remoteConfig } from "hot-updater/plugins";
import { bare } from "@hot-updater/bare";
import { fromNodeProviderChain } from "@aws-sdk/credential-providers";
import { defineConfig } from "hot-updater";
import { existsSync } from "node:fs";

if (existsSync(".env.hotupdater")) {
  process.loadEnvFile(".env.hotupdater");
}

const awsOptions = {
  region: process.env.HOT_UPDATER_S3_REGION!,
  credentials: fromNodeProviderChain(),
};

export default defineConfig({
  build: bare({ enableHermes: true }),
  storage: s3Storage({
    ...awsOptions,
    bucketName: process.env.HOT_UPDATER_S3_BUCKET_NAME!,
  }),
  database: dynamoDB({
    ...awsOptions,
    tableName: process.env.HOT_UPDATER_DYNAMODB_TABLE_NAME!,
    cloudfrontDistributionId: process.env.HOT_UPDATER_CLOUDFRONT_DISTRIBUTION_ID!,
  }),
  plugins: [apiKeys(), insights(), remoteConfig()],
  updateStrategy: "appVersion", // or "fingerprint"
});

If you choose shared AWS profile, fromNodeProviderChain() is replaced with fromIni({ profile: process.env.HOT_UPDATER_AWS_PROFILE! }) from the same package. SSO uses fromSSO({ profile: process.env.HOT_UPDATER_AWS_PROFILE! }) from @aws-sdk/credential-provider-sso. Init installs the package the config imports as a dev dependency: @aws-sdk/credential-providers for the default session and shared profile, @aws-sdk/credential-provider-sso for SSO. Only account/access-key mode emits a literal access-key credential block.

Replace account access keys (optional)

By this point, .env.hotupdater already contains the settings selected during hot-updater init.

This step applies only if you selected account/access-key mode during init. Current AWS CLI/default session, shared-profile, and SSO modes use their generated credential providers and do not read these two variables.

The account-mode credentials entered during infrastructure setup may have broader permissions than ongoing deployment requires.

Replace those credentials with a permanent least-privilege identity that can write bundle artifacts to S3, read and write the selected DynamoDB table, and invalidate the CloudFront distribution.

.env.hotupdater
HOT_UPDATER_S3_ACCESS_KEY_ID=your-access-key-id
HOT_UPDATER_S3_SECRET_ACCESS_KEY=your-secret-access-key

Step 4: If you use Expo, add the config plugin

Follow the Expo path in Set up your app. It applies the config plugin and generates the native integration. For DOM components, continue with Expo DOM components.

Step 5: Add native code

For Bare or Rock, follow the Android and iOS instructions in Set up your app. Keep the integration appropriate to your React Native version and rebuild the native app after changing it.

Upgrade infrastructure

With the Hot Updater skill attached, ask your agent:

$hot-updater Upgrade this project's existing AWS server infrastructure.

The agent discovers the existing deployment, uses hot-updater agent infra upgrade, and reads the applicable version files before changing resources. It applies pending changes and verifies the server with doctor. See Upgrade an existing server for the workflow or Doctor for terminal instructions.

For server templates to apply with your own deployment tooling, use hot-updater infra scaffold --provider aws. See Infrastructure Templates.

Verifying the setup

  1. Confirm the selected AWS resources and the deployed client base URL.

  2. From the React Native project, check the server and native integration:

    npx hot-updater doctor --server-base-url <client-base-url> --json

    Doctor checks the public /version endpoint. It does not prove an authenticated update download or application.

  3. Complete Test an OTA update on a release build. Verify that the app downloads and runs the changed code, then survives a restart.

An agent should report the selected resources, verified URL, configuration file paths and verification result. Report a missing access, billing or native-build prerequisite explicitly instead of marking an untested installation complete.

Host the Console

Host the console on Vercel, Netlify, or Docker/Node with AWS SDK credentials for the existing DynamoDB and S3 resources. ECS/Fargate is another option when you want an AWS task role. See the console hosting matrix.

On this page