Forced and mandatory updates for Capacitor apps
Sometimes an update cannot wait for the next cold start. How to ship immediate, mandatory OTA updates in Capacitor with OtaKit using force-immediate releases and update policies.
Most over-the-air updates can wait for the next cold start — the user closes the app, reopens it later, and quietly gets the new version. But some updates can't wait: a security fix, a broken payment flow, a change your backend now requires. For those you need a forced, immediate update. This guide covers how to do that with OtaKit without being heavy-handed.
Mental model: the default is patient (apply on next launch). A forced update is the exception you reach for when “later” isn't acceptable.
The two levers: policy and force-immediate
OtaKit separates what happens from when. Update policies (launchPolicy, resumePolicy, runtimePolicy) control the normal cadence — download in the background, apply on next start. For an urgent release, you override that at release time.
Ship an immediate update
Releasing with --force-immediate tells devices to apply and reload the new bundle on their very next check, instead of waiting for a cold start:
npm run build otakit upload --release --force-immediate
Use this sparingly. An immediate reload interrupts whatever the user is doing, so reserve it for genuine emergencies — not routine releases. For everything else, the default background-then-next-launch behavior is a better experience.
Build a “mandatory update” gate yourself
Sometimes you want the app to block until it's on a minimum version — for example when the API contract changed. You can implement this in your own code by listening for update events and gating the UI until the required bundle is active:
import { OtaKit } from "@otakit/capacitor-updater";
// download and apply the staged update, then reload
OtaKit.addListener("updateStaged", async () => {
await OtaKit.apply(); // reloads into the new bundle
});Pair that with a version check against your backend: if the device is below the minimum supported version, show a blocking “updating” screen until the new bundle applies. See the events docs for the full listener surface.
Don't forget: OTA can't force native updates
A forced OTA update only moves the web layer. If the thing that must change is native — a plugin, a permission, the Capacitor runtime — no OTA flag can deliver it; that's a store release. For those, the “mandatory update” you build should point users to the store. Know the line: see what OTA can and can't change.
Rule of thumb: background updates by default, --force-immediate for emergencies, and a self-built version gate only when the app genuinely can't function on an old bundle.
Where to go next
See background vs foreground update UX for the everyday case, and update strategies for the full policy matrix.