HotupdaterHot Updater
Self Hosting (Custom)

Quick Start

Since v0.22.0+

Get started with a self-hosted Hot Updater server in 5 minutes.

Installation

Install all required dependencies at once.

npm install @hot-updater/server @hot-updater/aws
npm install hono @hono/node-server
npm install kysely better-sqlite3 @types/better-sqlite3 --save-dev

Database Setup

Create the database connection file.

src/kysely.ts
import { Kysely, SqliteDialect } from "kysely";
import Database from "better-sqlite3";

export const db = new Kysely({
  dialect: new SqliteDialect({
    database: new Database("./data/database.db"),
  }),
});

Hot Updater Configuration

Create the Hot Updater instance with your database adapter and storage plugin (see Storage Plugins).

src/hotUpdater.ts
import { createHotUpdater } from "@hot-updater/server";
import { kyselyAdapter } from "@hot-updater/server/adapters/kysely";
import { s3Storage } from "@hot-updater/aws";
import { db } from "./kysely";

export const hotUpdater = createHotUpdater({
  database: kyselyAdapter({ db, provider: "sqlite" }),
  storages: [
    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!,
    }),
  ],
  basePath: "/hot-updater",
  routes: {
    updateCheck: true,
    bundles: true,
  },
});

By default, createHotUpdater mounts update-check routes and /version. Bundle management routes used by the CLI standaloneRepository plugin must be enabled explicitly and protected by framework middleware before mounting the handler. When you provide routes, specify both configurable route groups explicitly.

Server Setup

Create the server entry point.

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

const app = new Hono();

app.use( 
  "/hot-updater/api/*", 
  bearerAuth({ token: process.env.HOT_UPDATER_AUTH_TOKEN ?? "" }), 
); 
app.mount("/hot-updater", hotUpdater.handler); 

serve({ fetch: app.fetch, port: 3000 }, (info) => {
  console.log(`Server running at http://localhost:${info.port}`);
});

Security Settings

The Hot Updater handler does not include built-in authentication. Always protect bundle management routes before mounting the handler.

Update-check routes are usually exposed for React Native clients, but that is a deployment choice:

  • /hot-updater/app-version/*
  • /hot-updater/fingerprint/*

The bundle management routes under /hot-updater/api/* are used by the CLI. They are mounted only when routes.bundles: true, and your framework middleware must protect each management request before mounting the handler. The server example above uses Bearer authentication for /hot-updater/api/*.

Set your auth token in environment variables:

HOT_UPDATER_AUTH_TOKEN=your-secret-auth-token

Schema Generation

Generate the database schema.

npx hot-updater db generate src/hotUpdater.ts --yes

Run Server

Start your server.

node src/index.ts

Your Hot Updater server is now running at http://localhost:3000/hot-updater!

CLI Configuration

Configure your Hot Updater CLI to connect to this self-hosted server.

hot-updater.config.ts
import { defineConfig } from "@hot-updater/core";
import { bare } from "@hot-updater/bare";
import { s3Storage } from "@hot-updater/aws";
import { standaloneRepository } from "@hot-updater/standalone";

export default defineConfig({
  build: bare(),
  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",
    commonHeaders: {
      Authorization: `Bearer ${process.env.HOT_UPDATER_AUTH_TOKEN}`,
    },
  }),
});

The storage plugin here must match the storages in your server's createHotUpdater configuration. Both use s3Storage in this example.

React Native Setup

Configure your React Native app to connect to this server.

App.tsx
import { HotUpdater } from '@hot-updater/react-native';

export default HotUpdater.wrap({
  baseURL: 'http://localhost:3000/hot-updater', 
  updateStrategy: 'appVersion', // or "fingerprint"
  fallbackComponent: ({ progress, status }) => (
    // ... Custom loading UI
  ),
  onError: error => {
    // ... Error handling
  },
})(App);

Next Steps

On this page