VM Patches
Fix your compiled Dart code on a live app, over the air. VM Patches replace the actual Dart that runs in the VM — the part a Runtime Bundle can't touch — so you can ship a real bug fix without waiting for store review.
When to reach for a VM Patch
If a change is a value — a limit, a URL, a toggle — a Runtime Bundle is simpler and works on any build. Reach for a VM Patch when the fix is in code: a wrong calculation, a null-check you forgot, a broken navigation flow, a crash in a specific screen. Anything you'd normally fix in a .dart file and re-ship through the store.
What a VM Patch can and can't change
- Your Dart application code — logic, widgets, fixes
- Adding, removing, or changing a Dart package your code uses (Android)
- Native code (Kotlin/Java, Swift/Objective-C)
- Native plugins, permissions, or the app manifest
- The Flutter engine or Dart SDK version
Requirements
VM Patches have two requirements that Runtime Bundles don't:
- Built with the Koolbase engine. The shipped binary must be built with
koolbase buildusing the Koolbase engine for your Flutter version — that's what contains the interceptor that applies patches. A stock Flutter build cannot receive VM Patches. - A matching engine for your Flutter version. Each Flutter version has its own Koolbase engine build. See Flutter Versions & Engines.
The integration
On the app side there's nothing extra to write — Koolbase.initialize() sets up the VM patch client (KoolbaseVmPatchClient) automatically. It checks the resolver, downloads, and stages patches for you.
await Koolbase.initialize(
KoolbaseConfig(
baseUrl: 'https://api.koolbase.com',
publicKey: 'pk_live_...',
codePushChannel: 'stable',
),
);
// VM patch client is now running. It will check for a patch matching
// this binary, stage it, and the engine applies it on the next launch.Applied before your code runs
Building and pushing a patch
When you have a fix, recompile your app binary and push a diff patch against the build that's live. The CLI builds, signs, uploads, and (with --publish) makes it live in one command:
koolbase patch push \
--app <project_id> \
--binary ./base/libapp.so \ # the build that's live
--new ./fixed/libapp.so \ # your recompiled fix
--diff \
--key ./private.key \
--platform android \
--channel stable \
--rollout 25 \
--publishOn iOS, you author the patch from your fixed Dart source and ship it in one command — the release build_id is derived from your binary automatically:
koolbase patch ios build \
--source lib/main.dart \
--app-package myapp \
--engine 3.44.4-koolbase.4
koolbase patch push-ios \
--app <project_id> \
--kbpi myapp_patch.kbpi \
--binary ./Runner.app/Frameworks/App.framework/App \
--key ./private.keySee the full command set, including stage-local, list, recall, and publish, in the CLI Reference.
Keep your base binary
Testing a patch locally
Before pushing to the server, you can build a patch and stage it directly on a device for testing with stage-local — useful while developing against the engine:
koolbase patch stage-local \
--binary ./base/libapp.so \
--new ./fixed/libapp.so \
--diff \
--key ./private.keySafety & compliance
Every patch is signature- and build_id-verified, diff patches are hash-checked after reconstruction, and a patch that fails to boot auto-reverts — the full chain is described in How It Works. Because VM Patches change app behavior, they carry compliance responsibilities: use them for fixes, not for shipping features around review. Read Store Compliance before using them on a production app.