Production control
Production control
Once OTA updates are working in Production, use release controls to roll out safely: gradual rollouts, mandatory updates, and rollbacks. New to Production? Work through Preparing for production first.
- React Native
- Capacitor
Examples assume codemagic-patch.config.json exists from cmpatch init. Set a default team with cmpatch config set team default-team or pass --team.
Examples assume the server is set with CODEMAGIC_PATCH_SERVER_URL or cmpatch-capacitor config set --server-url. Pass --team if your account belongs to more than one team. Commands ask for confirmation in a terminal; pass --yes to skip it.
For the Staging → Production workflow, see Releasing updates.
Gradual rollout
Rollouts deliver an update to only a percentage of eligible users first.
- React Native
- Capacitor
cmpatch release-react --platform ios --deployment Production \
--rollout-percentage 25 --release-notes "Gradual rollout" --yes
cmpatch-capacitor release create --bundle-path www \
--app MyApp-iOS --deployment Production --target-binary-version "1.2.0" \
--rollout-percentage 25 --release-notes "Gradual rollout"
Typical progression:
Release at 10% → monitor → increase → 50% → 100%
Adjust an existing rollout without republishing:
- React Native
- Capacitor
cmpatch release patch --app MyApp-iOS --deployment Production --label v5 \
--rollout-percentage 50 --yes
cmpatch-capacitor release patch --app MyApp-iOS --deployment Production --label v5 \
--rollout-percentage 50
The rollout percentage can only be increased. release patch cannot change the target binary version of a Capacitor release; see Binary version compatibility.
Rollout constraints
- One partial rollout per deployment at a time
- Complete or disable the current rollout before publishing another update to the same deployment.
release inspect --waitonly waits for the release worker; it does not finish a rollout - Rollout percentage must be between 1 and 100
These constraints prevent users on the same deployment from receiving conflicting versions.
Mandatory updates
Mark critical fixes as mandatory so eligible clients apply them under mandatoryInstallMode without waiting for installMode conditions:
- React Native
- Capacitor
cmpatch release-react --platform ios --deployment Production --mandatory --yes
cmpatch-capacitor release create --bundle-path www \
--app MyApp-iOS --deployment Production --target-binary-version "1.2.0" --mandatory
On the client, mandatoryInstallMode controls when that apply happens (default: IMMEDIATE). See Applying updates.
Reserve mandatory updates for:
- Critical crashes or data corruption
- Security issues
- Breaking API changes
If a device skipped an older mandatory release in the deployment history, a later compatible update may still be treated as mandatory until the user catches up.
Disable and re-enable
Temporarily stop serving a release without deleting it:
- React Native
- Capacitor
cmpatch release disable --app MyApp-iOS --deployment Production --label v3 --yes
cmpatch release enable --app MyApp-iOS --deployment Production --label v3 --yes
cmpatch-capacitor release disable --app MyApp-iOS --deployment Production --label v3
cmpatch-capacitor release enable --app MyApp-iOS --deployment Production --label v3
When a release is disabled, the deployment serves the previous release instead, including to devices that already installed the disabled one. Devices switch on their next update check: the next launch, or the next foreground return with CheckFrequency.ON_APP_RESUME.
Roll back to the previous release
Manual rollback for production incidents:
- React Native
- Capacitor
cmpatch release rollback --app MyApp-iOS --deployment Production --yes
cmpatch-capacitor release rollback --app MyApp-iOS --deployment Production
Rollback creates a new release with its own label, using the bundle of the previous release (or of the release given with --label).
Automatic rollback
- React Native
- Capacitor
The SDK rolls back if a new bundle crashes before notifyAppReady() runs. Because sync() calls notifyAppReady() first on startup, the default integration arms this protection automatically.
The SDK rolls back a new bundle that does not call notifyAppReady() within maxLaunchAttempts launches (default 3). start() and sync() call notifyAppReady() first, so calling start() after the first screen renders enables this protection.
If you use manual control instead of sync(), you must call notifyAppReady() after a successful boot, otherwise healthy updates can be reverted.
Promote from Staging to Production
- React Native
- Capacitor
cmpatch release promote \
--app MyApp-iOS \
--source-deployment Staging \
--dest-deployment Production \
--label v4 \
--yes
cmpatch-capacitor release promote \
--app MyApp-iOS \
--source-deployment Staging \
--dest-deployment Production \
--label v4 \
--rollout-percentage 10
Promote reuses the bundle tested in Staging without re-uploading it. It accepts --rollout-percentage, --mandatory / --not-mandatory, --release-notes, and --disabled.
Example production workflow
release to Staging → validate
→ promote to Production at 10% rollout
→ monitor metrics
→ increase rollout or mark mandatory if critical
→ rollback if issues appear
See Analytics for monitoring.