Native Compatibility
How Capgo detects native package drift and what incompatible means for devices.
Copy a setup prompt with the install steps and the full markdown guide for this plugin.
A common Capgo setup uses a dev channel and a production channel. CI uploads every OTA bundle to dev, then promotes to production when you are ready. Teams often add --fail-on-incompatible so CI cannot ship a live update that needs new native code by accident.
This page answers the follow-up: what do you do when you intentionally need a bundle that is incompatible with the channel’s current native packages?
If you need the background on why Capgo compares native packages, start with Native Compatibility. For a full CI branch that picks OTA vs Capgo Build automatically, see Auto OTA or Native.
This guide assumes the dev and production channels already exist. Create them first if needed:
npx @capgo/cli@latest channel add production com.example.appnpx @capgo/cli@latest channel add dev com.example.app| Channel | Who gets it | Typical upload |
|---|---|---|
dev | Internal / QA builds | Every CI push of JS (and intentional native baselines) |
production | Store users | Promoted or uploaded only when release-ready |
--fail-on-incompatible is a good default on both channels for everyday OTA uploads. It compares the native packages in the bundle you are uploading against the bundle currently live on that channel. If they differ, the upload exits non-zero and nothing ships.
When the change is JavaScript-only and native packages match the channel:
npx @capgo/cli@latest bundle upload com.example.app \ --channel production \ --fail-on-incompatible \ --auto-min-update-version--fail-on-incompatible blocks accidental native drift. --auto-min-update-version is required on every upload once the channel uses the metadata strategy (recommended below). If the channel is not on metadata yet, you can omit --auto-min-update-version until you switch.
Optional CI gate before upload:
npx @capgo/cli@latest bundle releaseType com.example.app --channel production# → OTA safe to upload with --fail-on-incompatible# → native stop; ship a native binary first (see below)You cannot upload a bundle that needs new native code while keeping --fail-on-incompatible. That flag exists to block exactly that case. When a plugin, Capacitor version, or other native dependency changed on purpose:
--fail-on-incompatible.--auto-min-update-version with the channel on the metadata strategy so devices still on the old binary do not receive the new bundle until they install the new app.--fail-on-incompatible back on normal OTA CI (and keep --auto-min-update-version while the channel stays on metadata).One-time per channel: enable metadata gating
npx @capgo/cli@latest channel set production com.example.app --disable-auto-update metadataRepeat for dev if that channel also receives intentional native baselines. After this switch, every upload to the channel must include --auto-min-update-version or --min-update-version.
Ship the native binary
Build and submit the iOS/Android app that includes the new plugins or native changes. Until users install that binary, they cannot safely run a bundle that depends on those native packages.
Upload the matching OTA baseline (no --fail-on-incompatible)
npx @capgo/cli@latest bundle upload com.example.app \ --channel production \ --auto-min-update-versionThis records the new native packages on the channel. Later bundle releaseType / --fail-on-incompatible checks use that baseline.
Resume guarded OTA uploads
Subsequent JS-only releases use both flags again:
npx @capgo/cli@latest bundle upload com.example.app \ --channel production \ --fail-on-incompatible \ --auto-min-update-version--fail-on-incompatible and still push a native-incompatible bundle?No. If the upload’s native packages differ from the channel’s live bundle, the flag fails the command on purpose. For an intentional native bump, omit the flag on that one upload (and use --auto-min-update-version when you can).
Yes. That is the supported way to advance the channel’s native baseline after you ship a new binary. Keep the flag on every other OTA upload so accidental native drift still fails CI.
dev first, then production?Yes, if that matches your process. Run the same rules per channel: the compatibility check is against whatever is live on the target channel. Promote or re-upload to production only after dev looks good, and use a native-baseline upload (no --fail-on-incompatible) on each channel that needs the new native packages recorded.
CI fails and Capgo does not ship that upload. That is the expected outcome. Either the change was accidental (fix the native packages and retry as OTA), or it was intentional (use the native path above).
| Path | When | Upload flags |
|---|---|---|
| OTA | JS-only; native packages match the channel | --fail-on-incompatible + --auto-min-update-version (required if the channel is on metadata) |
| Native baseline | New native binary + matching JS bundle | No --fail-on-incompatible; keep --auto-min-update-version |
Native Compatibility
How Capgo detects native package drift and what incompatible means for devices.
Auto OTA or Native
Wire bundle releaseType into GitHub Actions or GitLab so CI picks the right path.
Version Targeting
Channels, semver rules, and the metadata strategy for delivery floors.
CLI: bundle
Reference for upload, compatibility, releaseType, and related flags.
If you are using Native + OTA Channel Workflow to keep live updates safe across native releases, connect it with Native Compatibility for the package comparison rules, Auto OTA or Native for CI branching, Version Targeting for metadata floors, and the Capgo CLI bundle reference for upload flags.