HotupdaterHot Updater

Adapters and Plugins

The adapters that build, sign, store, and hold updates, the plugins that extend the server and the app, and how to write your own.

Adapters and plugins

Hot Updater talks to bundlers, cloud services, and databases through two kinds of objects:

  • An adapter fills one slot of a configuration: the build, storage, database, or signing of hot-updater.config.ts, and the database and storage of the server's createHotUpdater. A configuration has one adapter per slot; the server's storage takes a list so it can read Bundles that different adapters stored.
  • A plugin is one entry of a list: the plugins of createHotUpdater, of hot-updater.config.ts, or of the app's HotUpdater.init, or an integration that wraps a build adapter. A configuration can have any number.

Both are plain objects that a factory function returns, such as s3Storage(options) or insights(). Official adapters and plugins use the same contracts as the ones you write, and there is no registry: install the package and pass the object in.

Plugins are configured in three places:

  • The server's createHotUpdater({ plugins }), for server plugins, beside the server's database and storage adapters.
  • plugins in hot-updater.config.ts, for the same server plugins. The config mirrors the server: its storage and database reach the server's bucket and database, or the server's admin API through standaloneRepository, and its plugins tell the CLI and the Console which plugins the server runs.
  • The app's HotUpdater.init({ plugins }), for client plugins.

A managed project lists plugins in two places: hot-updater.config.ts, where init imports apiKeys, insights, and remoteConfig from hot-updater/plugins and lists [apiKeys(), insights(), remoteConfig()], and the app. Its prebuilt server runs the same server plugins.

Keep the config's list the same as the server's, and a deployed Console's console.config.ts, which mirrors the server too. When the server adds or drops a plugin, change each list with it, or import one list from a module every project can reach.

KindWhat it doesRuns inOfficialWrite one
Build adapterBundles the app's JavaScript for hot-updater deployCLIBare, Expo, RockBuildAdapter from @hot-updater/plugin-core
Storage adapterStores bundle artifacts and resolves their download URLsCLI, Console, serverSupabase, Cloudflare R2, AWS S3, Firebase, StandaloneCreate a storage adapter
Database adapterStores Bundles, Releases, Release Catalogs, Channels, and server plugins' tablesCLI, Console, serverSupabase, Cloudflare D1, DynamoDB, Firestore, Kysely, Drizzle, Prisma, MongoDBCreate a database adapter
Signing adapterSigns artifact hashes during deployCLILocal PEM, AWS KMS, Google Cloud KMS, remoteBundleSigningAdapter from @hot-updater/plugin-core
Server pluginAdds tables, APIs, routes, and client authentication to the update serverServer, and the CLI and Console over a direct database; its tables come from managed init or hot-updater db in the server projectinsights(), apiKeys(), remoteConfig()Create a server plugin
Client pluginObserves launches, update checks, downloads, and failures in the app, and calls the serverReact Native appInsights, Remote ConfigCreate a client plugin
Integration pluginUploads source maps for the bundles a build adapter makesCLISentry, Datadog, BugSnagA function that wraps a build adapter

The managed Cloudflare, Supabase, AWS, and Firebase servers are prebuilt with their provider's storage and database adapters and the official server plugins, Insights, API keys, and Remote Config. Other adapters and server plugins run on a custom server. Client plugins run in any app.

A feature can ship both halves, as Insights does: a server plugin that stores data and serves routes, and a client plugin that calls those routes with the app's base URL and headers. The server plugin names its client plugin in cli.clientPlugin, which managed init and the agent scaffold use to add it to the app's HotUpdater.init, and which hot-updater doctor checks the app for.

Write your own

Pick the contract for the slot or the list, and write a factory that returns it. Each guide builds one and tests it:

KindContractGuide
Storage adaptercreateStorageAdapter from @hot-updater/plugin-coreCreate a storage adapter
Database adaptercreateSqlAdapter, createKvAdapter, or a DatabaseAdapter, wrapped by createEngineDatabase from @hot-updater/plugin-coreCreate a database adapter
Server plugindefinePlugin from @hot-updater/plugin-coreCreate a server plugin
Client plugindefineClientPlugin from @hot-updater/protocolCreate a client plugin
Signing adapterBundleSigningAdapter from @hot-updater/plugin-core: getPublicKey and signRemote Signing describes the service protocol
Build adapterA function from { cwd } to a BuildAdapter from @hot-updater/plugin-coreThe official build adapters are the reference

Hot Updater's packages divide by where their code runs:

PackageWhat it holdsImported by
@hot-updater/protocolThe device-safe, zero-dependency package for what crosses a boundary: the data formats and pure computations the app and the server share, and the contracts between a host and its extensions on the device, such as the client plugin contract.The app, the server, the CLI, and client plugins
@hot-updater/plugin-coreThe kit that extends the server: the adapter and server plugin contracts and their helpers, and the storage engine they run on. It runs wherever the server runs, and depends on @hot-updater/protocol.Adapters and server plugins, including Hot Updater's own
@hot-updater/serverThe runtime host: createHotUpdater and its handlers, with the built-in adapters and plugins it re-exports.The server and deployed Console
hot-updater/pluginsThe official server plugin factories for CLI configuration: apiKeys, insights, and remoteConfig.hot-updater.config.ts
@hot-updater/react-nativeThe app's SDK. It imports @hot-updater/protocol and the built-in Insights and Remote Config clients, never @hot-updater/plugin-core or the server.The app

An adapter or a server plugin you write imports @hot-updater/plugin-core, and a client plugin imports @hot-updater/protocol, as Hot Updater's own plugin packages do. A database adapter builds on the engine kit there too. @hot-updater/react-native re-exports the client plugin names for app code.

Each package's API is its root. A subpath only sets apart a part some projects leave out: @hot-updater/server/adapters/* holds the Kysely, Drizzle, Prisma and MongoDB adapters, @hot-updater/server/plugins the built-in plugins, and an official plugin package has one entry per side. No package has an internal entry, and a package uses another only through that package's API. Test helpers live in @hot-updater/test-utils alone.

Then package it for npm with Hot Updater as a peer dependency; see Test and publish.

Community adapters and plugins

Community adapters and plugins are npm packages that use the contracts above. Search npm for the hot-updater-adapter and hot-updater-plugin keywords to find them. Hot Updater does not review or maintain them: read a package's source and its tested Hot Updater versions before you install it. To list yours here, open a pull request in the Hot Updater repository.

Build adapter

Build adapters generate JavaScript bundles when you run hot-updater deploy.

  • @hot-updater/bare: Runs the project's configured bundler through the React Native CLI bundle command.
  • @hot-updater/rock: Runs the project's configured bundler through the Rock CLI bundle command.
  • @hot-updater/expo: Executes the bundle command through Expo.

Storage adapter

Storage adapters upload generated bundles to your chosen provider during hot-updater deploy, and the server resolves the URLs devices download them from.

Storage adapters expose one flat, runtime-independent byte contract. CLI and server consumers validate only the operations they need. Provider packages can export the same adapter name from runtime-specific subpaths; for example, @hot-updater/cloudflare uses S3-compatible credentials while @hot-updater/cloudflare/worker captures an R2 binding.

  • @hot-updater/supabase: Stores bundles in Supabase with supabaseStorage.
  • @hot-updater/cloudflare: Provides deploy-time r2Storage and Worker runtime storage for Cloudflare R2.
  • @hot-updater/aws: Stores bundles in AWS S3 with s3Storage.
  • @hot-updater/firebase: Stores bundles in Firebase Storage with firebaseStorage.
  • @hot-updater/standalone: Sends storage operations to your own HTTP service with standaloneStorage.

To write one, see Create a storage adapter.

Database adapter

Database adapters persist immutable artifact metadata, Release policy, compiled Catalogs and Channels, and the tables of the server plugins a server runs, such as Insights, API keys, and Remote Config. Deploy and administrative operations commit changes atomically. The server uses the same database for Catalog reads, artifact resolution and its plugins; the device selects an update from the returned Catalog.

Core and server plugins declare their tables and run their reads and transactions on one storage engine, so a database adapter only stores rows and reads index ranges on its backend.

  • @hot-updater/supabase: Stores metadata in Supabase with supabaseDatabase.
  • @hot-updater/aws: Provides dynamoDB for metadata.
  • @hot-updater/cloudflare: Stores metadata in Cloudflare D1 with d1Database.
  • @hot-updater/firebase: Stores update metadata in Firebase Firestore with firebaseDatabase.
  • @hot-updater/standalone: standaloneRepository reaches a self-hosted server's database through its admin API, as the database of hot-updater.config.ts or of the Console's configuration.
  • Kysely, Drizzle, Prisma, and MongoDB connect an existing database to a custom server.

To run on another backend, see Create a database adapter.

Signing adapter

Signing adapters authenticate immutable OTA artifact content during hot-updater deploy. They resolve the provider public key and sign the 32 raw bytes decoded from each SHA-256 artifact hash. The deploy command verifies every returned RSA-SHA256 signature before upload and checks that the signer identity matches the native app trust anchor.

Signing is independent of the storage and database adapters. Omit signing or set local enabled: false for unsigned deployments; Hot Updater never falls back from an enabled signer to an unsigned deployment.

  • Built-in local signing: Use enabled: true and privateKeyPath. Signing is never enabled automatically.
  • hot-updater/signing: Use a compatible signing endpoint with remoteSigning, or hardened managed-key custody with awsKmsSigning and googleCloudKmsSigning.

Expo projects configure the native trust anchor independently through the @hot-updater/expo app plugin's publicKeyPath. This keeps EAS builds outside the private-key and KMS credential boundary.

The cloud KMS SDKs are optional peer dependencies and load only when their signer is used for deployment.

See Bundle Signing for custody differences, provider setup, native trust-anchor rollout, and rotation guidance.

Integration plugins

Integration plugins connect bundle builds to error-monitoring services. They wrap your selected build adapter to upload source maps and associate them with the deployed update. The app's monitoring SDK must use matching identifiers for readable stack traces.

Each guide covers service credentials, build configuration and symbolication verification. These integrations can be used with any hosting, storage and database choice supported by the selected build workflow.

Server plugins

Server plugins extend the update server rather than the CLI. They run inside createHotUpdater, own tables and aggregates on the server's database, and add APIs, routes and client authentication. Core has none of their tables or routes: a server has Insights only when it runs the insights() plugin, which records Insights reports, apiKeys() protects client routes, and remoteConfig() serves Remote Config. Managed providers run all three. To write one for a custom server, see Create a server plugin.

Hot Updater's own plugins are packages built the same way: @hot-updater/plugin-insights, @hot-updater/plugin-api-keys, and @hot-updater/plugin-remote-config. @hot-updater/server/plugins re-exports them for servers and deployed Consoles. CLI configurations import these factories from hot-updater/plugins, which ships with the CLI. Each package has an entry per side, the layout a plugin you publish follows; see Ship both sides from one package.

The Console has built-in screens for these official features, and shows each one only when its configuration lists the plugin, as the server runs it. It has no UI extension API: a plugin extends the server and the app, and its data reaches people through its API and its routes.

Client plugins

Client plugins run in the React Native app. They observe launches, update checks, downloads, and update failures, and can send requests to the update server with the app's base URL and headers. Pass them to plugins in HotUpdater.init, which returns the app's HotUpdater instance with each plugin's API under the plugin's id, as the server's hotUpdater.api holds server plugins' APIs. The Insights plugin reports to the server's insights() plugin; it is @hot-updater/plugin-insights/client, which @hot-updater/react-native exports from its root. The Remote Config plugin, from @hot-updater/plugin-remote-config/client, fetches the values the server's remoteConfig() plugin picks and reads them synchronously. To write one, see Create a client plugin.

On this page