Bundling And Distribution
When your app is ready to leave your machine, one command produces everything distribution needs: the application bundle, a compressed update archive, a platform installer, update metadata, and optionally a delta patch from your previous release. This page explains what those artifacts are, what they’re named, and where to put them.
Hutch builds for the current host platform. Use canary builds for testing and
stable builds for user-facing releases — the two channels are
independent, so testers can run prerelease builds alongside the stable
app. A typical project wires both into hutch.config.ts:
export default { scripts: { install: ["hutch", "install", "--frozen-lockfile"], dev: ["hutch", "electrobun", "dev", "--watch"], "build:canary": ["hutch", "electrobun", "build", "--env=canary"], "build:stable": ["hutch", "electrobun", "build", "--env=stable"], },};electrobun.version is optional: npm-launched commands use the installed
package’s paired version. A direct Hutch project selects the active release
channel initially, then prepare, build, run, and dev preserve its
projected release; an explicit sync advances it. An exact pin overrides all
of those defaults.
hutch run installhutch run build:canaryhutch run build:stableRelease Host
Artifacts are flat files and can be served from R2, S3, another object store, or any static HTTP host. Configure the public folder URL:
import type { ElectrobunConfig } from "electrobun";
export default { app: { name: "My Cool App", identifier: "com.example.my-cool-app", version: "1.0.0", }, build: { mainProcess: "cottontail", cottontail: { entrypoint: "src/bun/index.ts" }, }, release: { baseUrl: "https://releases.example.com/my-cool-app", generatePatch: true, },} satisfies ElectrobunConfig;Upload the contents of artifacts/ without renaming the files. The Updater
constructs URLs from this base and the channel/platform prefix.
Host-Native Matrix
Run the same build on each published target:
| Runner | Stable installer prefix | Stable updater prefix |
|---|---|---|
| macOS ARM64 | macos-arm64- | stable-macos-arm64- |
| Windows x64 | win-x64- | stable-win-x64- |
| Linux x64 | linux-x64- | stable-linux-x64- |
| Linux ARM64 | linux-arm64- | stable-linux-arm64- |
Canary builds prepend canary- to both prefixes. Windows ARM uses
the x64 artifact through system emulation. Electrobun’s current release matrix
does not publish a macOS x64 core artifact.
Artifact Names
Hutch removes ASCII spaces from the app name in artifact filenames. For an app
named My Cool App, a macOS ARM64 canary build produces:
artifacts/|-- canary-macos-arm64-update.json|-- canary-macos-arm64-MyCoolApp-canary.dmg|-- canary-macos-arm64-MyCoolApp-canary.app.tar.zst`-- canary-macos-arm64-<previous-hash>.patchA Windows x64 canary build produces:
artifacts/|-- canary-win-x64-update.json|-- canary-win-x64-MyCoolApp-Setup-canary.zip|-- canary-win-x64-MyCoolApp-canary.tar.zst`-- canary-win-x64-<previous-hash>.patchThe Windows zip contains the visible setup executable and a hidden installer payload. The executable retains the display name’s spaces.
A Linux x64 canary build produces:
artifacts/|-- canary-linux-x64-update.json|-- canary-linux-x64-MyCoolApp-canary-Setup.tar.gz|-- canary-linux-x64-MyCoolApp-canary.tar.zst`-- canary-linux-x64-<previous-hash>.patchThe Linux installer archive contains an executable named installer and a
README. Stable installer names omit both the channel prefix and -canary:
macos-arm64-MyCoolApp.dmgwin-x64-MyCoolApp-Setup.ziplinux-x64-MyCoolApp-Setup.tar.gzStable update JSON, compressed archives, and patches retain the
stable-<os>-<arch>- protocol prefix used by compatible Electrobun v1.18.1+
clients. Installer artifacts do not use that prefix. Keep the app name,
identifier, and existing update base URL unchanged for the first 2.0 release;
see Updates.
Delta Patches
When release.generatePatch is true and release.baseUrl is present, Hutch:
- Fetches
<channel>-<os>-<arch>-update.jsonfrom the release host. - Downloads that release’s
.tar.zstupdate archive. - Decompresses it and creates a binary patch to the new uncompressed tar.
- Names the patch after the previous bundle hash.
The first release has no predecessor and therefore no patch. A missing or
invalid previous artifact also skips patch generation while preserving the
full update archive. Set generatePatch: false for an intentional build that
must not consult the release host.
Each release contributes one <previous-hash>.patch. Static hosts that retain
those immutable files form a patch trail, so an app several releases behind can
apply successive patches until its current hash equals update.json.hash. A
missing or failed patch falls back to the full archive named in the metadata.
See Updater for application-side checks, downloads, and installation.
See Uninstalling for the standalone uninstaller included with installer builds and how it treats application data.
Platform Packaging
macOS
Hutch emits a DMG by default and an .app.tar.zst update archive. Release
signing and notarization run when configured. Set build.mac.createDmg: false
when a release only needs the app and update archive.
Windows
Hutch emits a zip containing a setup executable and adjacent hidden payload. The installed application is a GUI-subsystem executable; dev launches attach to the invoking console.
Linux
Hutch emits a .tar.gz installer containing a self-extracting setup and a
.tar.zst update archive. Optional Flatpak configuration emits a separate
expanded payload and flatpak-builder manifest; Hutch does not run
flatpak-builder.
Build Hooks
preBuild, postBuild, postWrap, and postPackage can validate inputs or
augment the package at defined stages. Their exact timing and environment are
documented in Build Configuration.