Skip to content

Native Compatibility

A Capgo live update replaces your app’s JavaScript bundle instantly, but it can’t change the native part of your app — the Capacitor/Cordova plugins, native dependencies, and native project configuration that are compiled into the installed binary. When a new bundle expects native code that the installed binary doesn’t have, the bundle is native-incompatible: Capgo can still deliver it, but it may crash or misbehave on devices that are still running the older native build.

This page explains how Capgo detects native compatibility, what an incompatible update means for your users, and how to ship native changes safely.

Every Capacitor app ships in two layers:

  • The native binary users install from the App Store / Play Store. It contains Capacitor, your native plugins, and native configuration.
  • The JavaScript bundle (your web app) that Capgo can update over the air.

A live update swaps only the JavaScript layer. If that new JavaScript calls a native plugin or API that isn’t compiled into the installed binary, the call fails at runtime — which can crash the app or silently break a feature. Put simply: Capgo cannot update native code, so a device running the old native build can’t safely run a bundle that was built against new native code.

When you upload a bundle — or run the check manually — Capgo compares the native packages in your local project (your Capacitor/Cordova plugins and their versions) against the native packages recorded for the bundle currently live on the channel:

  • If they match, the change is JavaScript-only and safe to ship over the air.
  • If a plugin was added, removed, or changed version, the bundle is native-incompatible — those changes only take effect once users install a new native binary.
Terminal window
bunx @capgo/cli@latest bundle compatibility com.example.app --channel production

The CLI prints a table of each native package with its local version, the version live on the channel, and a status:

Package Local Remote Status
@capacitor/core 6.1.2 6.1.2 ✅
@capacitor/share 6.0.0 6.0.0 ✅
@capacitor/camera 6.1.0 — ❌ not in the live bundle

For pipelines, bundle releaseType collapses the check into a single word:

Terminal window
bunx @capgo/cli@latest bundle releaseType com.example.app --channel production
# → OTA safe to ship as a live update
# → native needs a new app-store build

Gate your release pipeline on this: ship a live update when it prints OTA, and trigger a native build when it prints native.

What an incompatible update means for your users

Section titled “What an incompatible update means for your users”

On devices still running the older native binary, the missing native code can cause crashes or broken features — even though the update downloaded and applied “successfully.” This is why a live update can be live and delivered yet still break the app for existing users, and why Capgo can warn you when an incompatible bundle goes live.

Capgo’s automatic rollback can catch a JavaScript error thrown before notifyAppReady() runs, but it isn’t a substitute for shipping compatible native code — a mismatch that crashes later, or crashes natively, can slip past it.

When a bundle needs new native code, build and submit a new binary to the App Store / Play Store (or rebuild with Capgo Cloud Build). Once users update the binary, the bundle’s native dependencies line up and the live update runs correctly.

Roll back if an incompatible bundle is already live

Section titled “Roll back if an incompatible bundle is already live”

If an incompatible bundle is already active on a channel, revert the channel to the last compatible build to stop serving it until the native build is out. See Rollbacks.

Two complementary guards, both of which actually inspect your native packages:

Fail the upload in CI — --fail-on-incompatible

Add the flag to your bundle upload step. If the bundle’s native packages don’t match the channel’s currently-live version, the upload fails with a non-zero exit and nothing is shipped — so your pipeline stops you from silently publishing an OTA update that can’t take effect until users install a native build:

Terminal window
bunx @capgo/cli@latest bundle upload --channel production --fail-on-incompatible

Compatible uploads — and cases where the check can’t run (a new channel, or no remote metadata) — pass through unchanged. In an interactive terminal it offers the Capgo Builder native-build flow instead; declining fails. (Can’t be combined with --ignore-metadata-check.)

Gate delivery by native version — metadata + --auto-min-update-version

When you do ship the native build and the bundle together, put the channel on the metadata strategy and upload with --auto-min-update-version. Capgo runs the compatibility check on every upload and, when a bundle needs new native code, raises the update floor so devices that haven’t installed the matching native build don’t receive it:

Terminal window
# one-time: switch the channel to the metadata strategy
bunx @capgo/cli@latest channel set production com.example.app --disable-auto-update metadata
# from then on, Capgo sets the floor automatically on every upload
bunx @capgo/cli@latest bundle upload --channel production --auto-min-update-version

See Version Targeting for the full set of targeting options.

If you are using Native Compatibility to keep live updates safe, connect it with Version Targeting to route bundles by native version, Rollbacks to recover when an incompatible bundle ships, Update Types to understand channel version blocking, and the Capgo CLI bundle reference for the compatibility and releaseType commands.