Releases & Patches

How VM Patches are organized: a release represents a binary you shipped, and patches are the ordered fixes you push on top of it. Understanding how devices are matched to a release is the key to pushing the right patch to the right users.

Releases

A release is a registered app binary — the build you shipped to a store (or sideloaded). It's the base that patches are applied against. When you push your first patch for a build, the CLI auto-creates the release if it doesn't exist — on iOS, patch push-ios derives the release's build_id from the binary you pass. Subsequent patches attach to the same release.

Each release belongs to a channel (e.g. stable or beta) and a platform. A device only ever receives patches from a release on its own channel.

Pushing a patch without the base binary

On Android, a patch is a diff against the base binary you shipped. When you register a release with koolbase release, the CLI now stores that base for you — so you don't have to extract libapp.so from your AAB by hand to push a patch later. (iOS patches aren't diffs, so this section applies to Android only.)

To push a patch against a stored base, pass --release <id> and omit --binary. The CLI fetches the stored base and diffs your new build against it:

# Patch a release whose base was stored at release time — no --binary
            koolbase patch push --app <id> --release <release_id> --new fixed.so --diff \
            --platform android --channel stable --publish

You still build your fixed code and pass it as --new — that's the update being shipped. Only the base is fetched for you.

Releases made before this still need --binary

Base storage applies to releases registered with a current CLI. A release created before this feature has no stored base, so patch push --release <id> without --binary will report that no base is stored. For those, either pass --binary <your base> as before, or ship a new release — from then on its patches need no --binary.

Passing --binary always works

--binary is never required to be omitted. If you provide it, the CLI uses the binary you pass and skips the fetch — useful for any release, stored base or not.

How a device matches a release

When the SDK checks in, it sends whatever identity it has for the running app. A release is registered to be matched one of two ways — its match mode:

  • build_id — a content hash of the compiled snapshot's instruction section, stamped by koolbase build. It identifies the exact compiled code: a change to only strings or assets keeps the same build_id; a logic change produces a new one. It survives Play App Signing and split-APK delivery intact, so it matches both sideloaded and Play Store builds.
  • release_version — the store versionName + versionCode (e.g. 1.4.0+503). Matches by the version you set rather than the exact binary, so you don't need to track the processed build's build_id. A convenient alternative for store workflows.

build_id wins when both are present

A device often sends both a build_id and a release_version. When a release exists for each, the build_id match takes precedence — it's the exact-binary identity, so it's authoritative. The release_version match is the fallback for store builds where the exact binary identity isn't available.

Choose the mode with --match-mode when pushing (defaults to build_id):

# Store app — match by version (survives Play re-signing)
            koolbase patch push --app <id> --release <release_id> --new fixed.so --diff \
            --match-mode release_version --app-version 1.4.0+503 \
            --platform android --channel stable --publish

Patches

A patch belongs to a release and carries a fix. Patches are auto-numbered per release — patch #1, #2, #3, in the order you push them. A device tracks which patch number it currently has applied.

The resolver always serves the highest published patch number for the matched release. If a device is on patch #2 and you publish #3, it picks up #3 on its next check. Patches are cumulative in intent — each new one represents the latest state of the fix, applied against the same base release.

Patch lifecycle

A patch is created as a draft, then published to go live (or pushed with --publish to do both at once). A published patch can later be recalled, which reverts devices — see Rollout & Rollback.

Channels

Channels let you ship to different audiences. The common setup mirrors Runtime Bundles:

ChannelUse case
stableProduction users. Push here once a patch is proven.
betaInternal testers or early adopters. Push here first.

The device's channel is set in KoolbaseConfig.codePushChannel at init. A release and its patches live on one channel; the same build released to two channels is two separate releases with independent patch sequences.

Inspecting releases & patches

List the patches on a release from the CLI:

koolbase patch list --release <release_id>

You can also view releases, patches, rollout state, and per-patch stats in the dashboard under your project's Code Push section.