Migrate from App Center CodePush
Plan a migration from Microsoft App Center CodePush to Otalan, with mapping notes, rollout guidance, and common failure modes.
Microsoft announced Visual Studio App Center retirement for March 31, 2025. Microsoft later extended Analytics and Diagnostics support, but states that the remaining App Center features retired after March 31, 2025. For CodePush, Microsoft points teams to a standalone CodePush server that can run independently from App Center.
Sources:
This page explains how to think about a migration from App Center CodePush to Otalan. It is not an automatic import tool.
Mental model mapping
| App Center CodePush concept | Otalan concept |
|---|---|
| App Center app | Otalan project app, usually the same mobile appId |
| Deployment, such as Staging or Production | Otalan channel |
| Deployment key in the installed app | OTA App Key plus exact app/channel/runtime settings |
| CodePush release package | Otalan bundle |
| Target binary version | runtimeVersion compatibility line |
| Promote release | Publish or roll out the same tested tuple/channel intentionally |
| Rollback | Reactivate an older Otalan bundle in the same tuple |
| CLI release automation | @otalan/cli bundle and publish flow |
The biggest difference is tuple strictness. Otalan always matches appId, platform, channel, and runtimeVersion exactly before serving an update.
Migration plan
- Inventory your CodePush apps, deployments, deployment keys, rollout rules, and target binary versions.
- Decide the Otalan
appId,platform,channel, andruntimeVersionmapping for each active release lane. - Create the Otalan organization, project, app registration, OTA App Key, and OTA Publish Key.
- Add the Otalan runtime integration for the app stack:
@otalan/capacitorfor Capacitor or@otalan/expowithexpo-updatesfor Expo. - Ship a new native binary that points to Otalan. Existing binaries that still point to CodePush will keep asking CodePush until users update the app.
- Configure CI with the OTA Publish Key and the same tuple values used by the runtime.
- Publish a canary bundle with
otalan bundleandotalan publish. - Verify the release path: publish one update, publish a second update, roll back, then confirm startup on the target devices.
- Freeze new CodePush publishes only after the Otalan-backed binary is available and verified.
- Keep old CodePush infrastructure or a compatibility plan for users who have not yet upgraded from old binaries.
Do not assume historical CodePush releases are imported into Otalan. Publish the known-good current bundle into Otalan and use that as the first rollback anchor.
Runtime integration notes
For Capacitor apps:
- install
@otalan/capacitor - keep
@capawesome/capacitor-live-update,@capacitor/app, and@capacitor/corealigned with the supported Capacitor range - put only the OTA App Key in the app
- keep OTA Publish Keys in local release tooling or CI
For Expo apps:
- install
@otalan/expo - keep
expo-updatesenabled - point the Expo update URL to the Otalan manifest endpoint
- include the OTA App Key in update request headers
- initialize
@otalan/expoonce and callupdater.check()forupdateAvailableorupdater.sync()for check-and-apply work - keep
checkAutomaticallycontrolled so Expo does not check before the Otalan helper is initialized
CI publishing pattern
A typical first Otalan CI job looks like this:
bun add -g @otalan/cli
otalan login --api-url "$OTALAN_API_URL" --api-key "$OTALAN_API_KEY"
otalan init --app-id "$OTALAN_APP_ID"
bun run build
otalan bundle --target capacitor --platform ios --runtime-version "$OTALAN_RUNTIME_VERSION"
otalan publish --channel "$OTALAN_CHANNEL" --release-notes "$GIT_COMMIT"
Use --target expo for Expo lanes, and publish iOS and Android separately when their generated assets differ.
Rollback flow
Rollback is server-side state change inside the same tuple:
- List bundles for the tuple with the dashboard or
otalan bundles. - Pick the last known-good bundle.
- Roll back with the dashboard or
otalan rollback. - Restart or re-check the app and confirm it receives the rolled-back bundle.
Rollback cannot switch native binary compatibility. If the broken release needs a different native plugin, permission, or runtime version, ship a store update and use a new runtimeVersion.
Common migration failure modes
- old installed binaries still point to CodePush because no new store binary was shipped
- CodePush deployment names were mapped to the wrong Otalan channels
runtimeVersionwas treated like a label instead of a native compatibility boundary- iOS and Android were published into the same lane even though their exported assets differ
- the app shipped an OTA Publish Key instead of an OTA App Key
- Expo update requests bypassed
updater.check()orupdater.sync()and ran before the Otalan helper initialized - dashboard manual Expo upload omitted
.otalan/bundle/manifest.json
Treat the migration as a release-platform change, not just a package rename.