HotupdaterHot Updater
Self Hosting (Custom)Server Frameworks

Hono

Build a self-hosted Hot Updater server with Hono framework.

Installation

Install Hono.

npm install hono

Setup and security

Set up a database adapter, generate its Hot Updater schema, and apply the schema before starting the server. Define the server in src/hotUpdater.ts with createHotUpdater, as in the quick start.

The recommended self-hosted setup runs the apiKeys() plugin, which requires an API key on update-check, Insights ingestion, and plugin client routes. Always protect admin routes with framework middleware before mounting the admin handler. Update-check routes are usually exposed for React Native clients, but that is a deployment choice:

  • Client OTA: /hot-updater/release-catalogs/*, /hot-updater/artifacts/*
  • Optional public diagnostics: /hot-updater/version
  • Protected admin API: /hot-updater/admin/*

The handlers are separate by construction. Mounting handlers.admin opts the server into the admin API; handlers.client never serves those routes. This example requires a nonempty token before mounting the admin handler:

src/index.ts
import { Hono } from "hono";
import { bearerAuth } from "hono/bearer-auth"; 
import { hotUpdater } from "./hotUpdater"; 

const app = new Hono();
const adminToken = process.env.HOT_UPDATER_ADMIN_TOKEN;

if (!adminToken) {
  throw new Error("HOT_UPDATER_ADMIN_TOKEN is required");
}

app.use( 
  "/hot-updater/admin/*", 
  bearerAuth({ token: adminToken }), 
); 

app.mount("/hot-updater/admin", hotUpdater.handlers.admin); 
app.mount("/hot-updater", hotUpdater.handlers.client); 

export default app;

Register the middleware first, then the specific admin mount, then the broader client mount. To run a client-only server, omit the admin middleware and admin mount entirely.

Set your auth token in environment variables:

HOT_UPDATER_ADMIN_TOKEN=your-secret-auth-token

Configure the CLI to include the auth token when deploying bundles, beside the config's storage and plugins; see CLI Configuration:

hot-updater.config.ts (excerpt)
import { standaloneRepository } from "@hot-updater/standalone"; 
import { defineConfig } from "hot-updater";

const adminToken = process.env.HOT_UPDATER_ADMIN_TOKEN;
if (!adminToken) {
  throw new Error("HOT_UPDATER_ADMIN_TOKEN is required");
}

export default defineConfig({
  // ... build, storage, plugins, and updateStrategy
  database: standaloneRepository({ 
    baseUrl: "http://localhost:3000/hot-updater/admin", 
    commonHeaders: { 
      Authorization: `Bearer ${adminToken}`, 
    }, 
  }), 
});

Handler boundaries

With insights() in plugins, handlers.client accepts Insights events and handlers.admin serves Insights queries; without it, the server has no such routes, and they answer 404. Apps send reports with the Insights client plugin. Server plugin endpoints mount on the same two handlers. The client API key protects catalog reads, artifact resolution, Insights ingestion, and plugin client routes; it does not protect or authorize the admin handler.

See the shared handler boundary for route groups and the repository server contract for exact management requests. Keep the framework-specific authentication and mount ordering shown above.

Before connecting the app, verify that /hot-updater/version responds and an admin request without the expected token is rejected. Then use CLI configuration to verify authenticated management access.

React Native setup

Create a client API key against the prepared database, then follow Set up your app. Use the client root as baseURL and send the key through x-api-key. Never put the admin token in the app.

For local connectivity checks, localhost reaches the host from the iOS Simulator on the same Mac and 10.0.2.2 does so from the Android Emulator. Before a release-build OTA test, expose the server through a reachable HTTPS endpoint and use it in the app; changing the host address does not enable cleartext HTTP. Complete Test an OTA update against that HTTPS endpoint.

On this page