HotupdaterHot Updater
Database Adapters

Kysely

Build a self-hosted Hot Updater server with Kysely query builder.

Before you start

Use this recipe in the server project from the custom-server quick start or your existing backend. Make the database and storage environment variables available to the server and schema commands. The React Native project's deploy configuration is a separate step.

kyselyAdapter supports PostgreSQL, MySQL 8.0 or later, and SQLite. CockroachDB and SQL Server are not supported.

Installation

Install Kysely and SQLite driver.

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

For other databases, see Kysely's dialect documentation.

Setup

Create a database connection file:

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

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

Hot Updater configuration

Create the Hot Updater instance:

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

export const hotUpdater = createHotUpdater({
  database: kyselyAdapter({ db, provider: "sqlite" }), 
  plugins: [insights(), apiKeys()],
  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!,
  }),
});

kyselyAdapter({ db, provider }) takes only these two options. It returns an engine database with the migrator that hot-updater db runs. provider is "postgresql", "mysql" or "sqlite" and must match the Kysely dialect. The adapter runs Hot Updater's shared SQL core on the Kysely instance, with one transaction per write; on SQLite, each transaction begins with BEGIN IMMEDIATE. insights() records app events, and apiKeys() protects the client routes with the x-api-key header.

Schema management

Generate an SQL migration file for Hot Updater's tables:

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

Apply the schema to the database:

npx hot-updater db migrate src/hotUpdater.ts

Generate vs Migrate

  • generate - Writes the SQL to hot-updater_migrations/ for review or for your own migration tool
  • migrate - Applies the same SQL to the database through Kysely

The SQL creates the tables and indexes, with no database foreign keys, then writes the schema settings rows last. The tables are core's and those of the server's plugins. db migrate runs it in one transaction on PostgreSQL and SQLite. Both commands read the database first and do nothing when its settings are current; run db migrate again after upgrading Hot Updater. They refuse a database created by an older Hot Updater schema instead of converting it; start from an empty database.

The server checks the settings rows before its first read or write. Until they exist, it throws HotUpdaterSchemaMigrationRequiredError and its handlers answer 503. A running server checks again on its next request, so it recovers once the migration has run.

Need plain SQL to apply yourself? See SQL Export for standalone SQL generation with the --sql flag.

CLI configuration

After the schema is applied, create the client API key using this same direct server configuration. Then connect the React Native project's CLI to the protected admin mount. Its storage configuration must match a server entry, and its plugins must list the server's plugins.

API endpoints

The adapter persists data; your framework mounts the HTTP handlers. Continue with the Hono, Express or Elysia recipe. See the handler boundaries and repository contract for client and admin access.

Finish with Set up your app and Test an OTA update.

On this page