Full documentation is available at: https://hot-updater.dev
Attach the Hot Updater agent skill so AI coding agents can use concise CLI
context for deploys, bundle management, rollbacks, and verification:
skills/hot-updater/SKILL.md
npx skills add hot-updater/skillsThen ask your agent with prompts like
$hot-updater deploy using the current app version or
$hot-updater roll back the most recently deployed bundle.
See the AI Agent Guide for the full workflow.
- Self-Hosted: Complete control over your update infrastructure
- Multi-Platform: Support for both iOS and Android
- Web Console: Intuitive update management interface
- Bundle Diffing: Reuse unchanged files and ship compact Hermes patches for smaller OTA downloads
- Plugin System: Support for various storage providers (AWS S3, Cloudflare R2 + D1, etc.)
- Version Control: Robust app version management through semantic versioning
- New Architecture: Support for new architecture like React Native
Hot Updater can deliver incremental OTA updates instead of making every
device download the full archive again. A diff-enabled runtime reuses bundle
files that already exist on the device, while deploys prepare .bsdiff
patches for changed Hermes bundles by default.
In practice, a release that would normally ship a 10 MB archive can be delivered as a ~600 KB patch when the Hermes bytecode change is small. If a patch is missing, incompatible, or not worth using, Hot Updater falls back to the normal archive update path.
See the Bundle Diffing guide for the full runtime behavior and fallback rules.
Hot Updater provides high extensibility through its plugin system. Each functionality like build, storage, and database is separated into plugins, allowing users to configure them according to their needs.
- Build Plugin: Support for bundlers like Metro, Re.Pack, Expo
- Storage Plugin: Support for bundle storage like AWS S3, Supabase Storage, Cloudflare R2 Storage
- Database Plugin: Support for metadata storage like Supabase Database, PostgreSQL, Cloudflare D1
import { bare } from "@hot-updater/bare";
import { supabaseDatabase, supabaseStorage } from "@hot-updater/supabase";
import { config } from "dotenv";
import { defineConfig } from "hot-updater";
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!,
}),
});import { bare } from "@hot-updater/bare";
import { d1Database, r2Storage } from "@hot-updater/cloudflare";
import { config } from "dotenv";
import { defineConfig } from "hot-updater";
config({ path: ".env.hotupdater" });
export default defineConfig({
build: bare({ enableHermes: true }),
storage: r2Storage({
bucketName: process.env.HOT_UPDATER_CLOUDFLARE_R2_BUCKET_NAME!,
accountId: process.env.HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID!,
cloudflareApiToken: process.env.HOT_UPDATER_CLOUDFLARE_API_TOKEN!,
}),
database: d1Database({
databaseId: process.env.HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID!,
accountId: process.env.HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID!,
cloudflareApiToken: process.env.HOT_UPDATER_CLOUDFLARE_API_TOKEN!,
}),
});import { bare } from "@hot-updater/bare";
import { s3Storage, s3Database } from "@hot-updater/aws";
import { config } from "dotenv";
import { defineConfig } from "hot-updater";
config({ path: ".env.hotupdater" });
const options = {
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(options),
database: s3Database(options),
});import { bare } from '@hot-updater/bare';
import {firebaseStorage, firebaseDatabase} from '@hot-updater/firebase';
import * as admin from 'firebase-admin';
import { config } from "dotenv";
import { defineConfig } from "hot-updater";
config({ path: ".env.hotupdater" });
// https://firebase.google.com/docs/admin/setup?hl=en#initialize_the_sdk_in_non-google_environments
// Check your .env file and add the credentials
// Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to your credentials file path
// Example: GOOGLE_APPLICATION_CREDENTIALS=./firebase-adminsdk-credentials.json
const credential = admin.credential.applicationDefault();
export default defineConfig({
build: bare({
enableHermes: true,
}),
storage: firebaseStorage({
projectId: process.env.HOT_UPDATER_FIREBASE_PROJECT_ID!,
storageBucket: process.env.HOT_UPDATER_FIREBASE_STORAGE_BUCKET!,
credential,
}),
database: firebaseDatabase({
projectId: process.env.HOT_UPDATER_FIREBASE_PROJECT_ID!,
credential,
}),
});