Skip to content

Native + OTA Channel Workflow

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:

Terminal window
npx @capgo/cli@latest channel add production com.example.app
npx @capgo/cli@latest channel add dev com.example.app
ChannelWho gets itTypical upload
devInternal / QA buildsEvery CI push of JS (and intentional native baselines)
productionStore usersPromoted 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:

Terminal window
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:

Terminal window
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)

Intentional native bump (drop the flag once)

Section titled “Intentional native bump (drop the flag once)”

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:

  1. Ship the matching native binary (App Store / Play Store, or Capgo Build).
  2. Upload the matching JS bundle without --fail-on-incompatible.
  3. Prefer --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.
  4. After that baseline upload, put --fail-on-incompatible back on normal OTA CI (and keep --auto-min-update-version while the channel stays on metadata).
  1. One-time per channel: enable metadata gating

    Terminal window
    npx @capgo/cli@latest channel set production com.example.app --disable-auto-update metadata

    Repeat 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.

  2. 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.

  3. Upload the matching OTA baseline (no --fail-on-incompatible)

    Terminal window
    npx @capgo/cli@latest bundle upload com.example.app \
    --channel production \
    --auto-min-update-version

    This records the new native packages on the channel. Later bundle releaseType / --fail-on-incompatible checks use that baseline.

  4. Resume guarded OTA uploads

    Subsequent JS-only releases use both flags again:

    Terminal window
    npx @capgo/cli@latest bundle upload com.example.app \
    --channel production \
    --fail-on-incompatible \
    --auto-min-update-version

Can I keep --fail-on-incompatible and still push a native-incompatible bundle?

Section titled “Can I keep --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).

Is a one-time upload without the flag the right approach?

Section titled “Is a one-time upload without the flag the right approach?”

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.

Do I upload to dev first, then production?

Section titled “Do I upload to 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.

What if I upload the new native bundle with the flag still on?

Section titled “What if I upload the new native bundle with the flag still on?”

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).

PathWhenUpload flags
OTAJS-only; native packages match the channel--fail-on-incompatible + --auto-min-update-version (required if the channel is on metadata)
Native baselineNew native binary + matching JS bundleNo --fail-on-incompatible; keep --auto-min-update-version

Keep going from Native + OTA Channel Workflow

Section titled “Keep going from Native + OTA Channel Workflow”

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.