CLI Configuration
Configure your Hot Updater CLI to connect to your self-hosted server.
Overview
Your CLI configuration (hot-updater.config.ts) connects your React Native
project to your self-hosted Hot Updater server. This file defines how bundles
are built, stored, and tracked, and it mirrors the server:
storageis the storage adapter the CLI uploads bundles with, one of the adapters the server lists increateHotUpdater({ storage }).databaseis the server's database: its database adapter, orstandaloneRepositoryto reach the server through its admin API.pluginslists the server plugins the server runs.
Basic configuration
Install the CLI dependencies in your React Native project. The config imports
the official server plugins from hot-updater/plugins:
npm install --save-dev @hot-updater/bare @hot-updater/aws @hot-updater/standalone hot-updaterCreate .env.hotupdater in that project with the server's R2_* storage values
and HOT_UPDATER_ADMIN_TOKEN, and add it to .gitignore. Then create
hot-updater.config.ts in the same project root:
import { existsSync } from "node:fs";
import { s3Storage } from "@hot-updater/aws";
import { bare } from "@hot-updater/bare";
import { standaloneRepository } from "@hot-updater/standalone";
import { defineConfig } from "hot-updater";
import { apiKeys, insights } from "hot-updater/plugins";
if (existsSync(".env.hotupdater")) {
process.loadEnvFile(".env.hotupdater");
}
const adminToken = process.env.HOT_UPDATER_ADMIN_TOKEN;
if (!adminToken) {
throw new Error("HOT_UPDATER_ADMIN_TOKEN is required");
}
export default defineConfig({
build: bare({ enableHermes: true }),
storage: s3Storage({
region: "auto",
endpoint: process.env.R2_ENDPOINT,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
},
bucketName: process.env.R2_BUCKET_NAME!,
}),
database: standaloneRepository({
baseUrl: "http://localhost:3000/hot-updater/admin",
commonHeaders: {
Authorization: `Bearer ${adminToken}`,
},
}),
plugins: [insights(), apiKeys()],
updateStrategy: "appVersion",
});The CLI storage adapter must match one entry in the server's
createHotUpdater({ storage }) list.
If the CLI uses s3Storage, the server must also use s3Storage.
Both sides need the same adapter and URI configuration to encode and decode
the hierarchical protocol://bucket/encoded/slash/key storage URIs correctly.
Mirror the server
List the same server plugins in plugins as the server's
createHotUpdater({ plugins }), and change the config whenever the server adds
or drops one. The CLI and the Console learn the server's plugins from it:
hot-updater doctorchecks that the app adds the client plugins they name.- The Console shows the features of the official plugins listed: through
standaloneRepository, the server's Insights overview, events, installations, update failures, and retention periods, and its Remote Config to edit, publish, and roll back. hot-updater remote-configandhot-updater insightswork on the same features as the Console, throughstandaloneRepositorytoo.hot-updater api-keymanages keys throughapiKeys(), over the server's database adapter.
With standaloneRepository, the server runs each change on its own database,
with its own plugins.
When the React Native project can reach the server's database, such as a deploy
job with the database's credentials, set database to the server's database
adapter instead, such as kyselyAdapter(...). The CLI then assembles core over
database and plugins as createHotUpdater does, and its commands write
through it, the path the server's own writes take:
- A plugin whose migration has not run stops a command before it reads or
writes. The error names the plugin and the fix. For a self-hosted server,
run
hot-updater db migrate, orhot-updater db generatefor a database migrated from files, in the server's project: thedbcommands load the server file, such assrc/hotUpdater.ts, and don't readhot-updater.config.ts. For a managed server, rerunhot-updater init --provider <provider>. A plugin the server doesn't run has no settings row, so listing one stops these commands too. - When a retention pass is due, a write first deletes expired rows of plugins' tables, such as Insights' events. The server and the CLI share one lease, due every hour, or every minute while a backlog remains. A pass deletes at most 500 rows a table. A pass that fails, such as for credentials that cannot delete, logs a warning and the write goes ahead; the pass is due again at once, so the next writer that can delete, such as the server, runs it.
- A write that changes a Release Catalog purges the CDN once.
Standalone Repository configuration
baseUrl is the exact root where the server mounts handlers.admin.
commonHeaders must match the authentication middleware on that mount. Keep
these values in the CLI's environment; the mobile app connects to the client
root with its own API key.
standaloneRepository takes only these two options. Its routes are the
server's admin API, so they cannot be remapped. See the
Standalone Repository reference
for alternate authentication headers.
Server plugins
With standaloneRepository, the server plugins
run only on the server. The Console reads the server's Insights overview,
events, installations, update failures, and retention periods from its admin
handler, and edits its Remote Config there, as hot-updater insights and
hot-updater remote-config do; App usage, bundle activity, and API key
management need the server's database adapter as database. To
manage API keys, run hot-updater api-key in the server project with the path
of the file that creates hotUpdater, as in
Manage API keys.
API endpoints
The repository server contract
is the canonical request and response reference. createHotUpdater implements
it through handlers.admin; no handwritten endpoint implementation is needed
when using that server. Protect the admin mount with framework middleware.
Verify the connection
Run a read-only command from the React Native project:
npx hot-updater bundle listA successful list, including an empty list for a new installation, verifies
the configured admin URL and credentials. A 401 means the CLI header and
server middleware do not agree. A 503 means the server's database is not
ready; if it needs migrations, run hot-updater db migrate where the server's
database is configured. A message to upgrade @hot-updater/server means the
server does not speak the admin API protocol this CLI needs. A successful list
does not verify the mobile client path.
Then set up your app with the client URL and API key, and test an OTA update in a release build.