Short answer: Mobile app CI/CD automates four jobs that teams otherwise do by hand: building the iOS and Android binaries, signing them, sending them to testers and releasing them to the stores in stages. For React Native with Expo, EAS Build and EAS Submit cover most of it; for Flutter or bare React Native, Fastlane on GitHub Actions or Codemagic is the common setup. Code signing is usually the hard part.
Key takeaways
- iOS needs a Mac: iOS builds run on macOS, and GitHub-hosted macOS minutes cost roughly ten times the Linux rate.
- Signing belongs in the pipeline: fastlane match keeps certificates and provisioning profiles encrypted in a private git repo, so CI and every developer sign with the same identity.
- OTA updates have limits: EAS Update and Shorebird ship JavaScript or Dart changes without a store release, but native changes still need a new build.
- Release in stages: App Store phased release spreads an update over seven days; Google Play staged rollouts reach a percentage of users that the team raises manually.
The pipeline, step by step
A typical pipeline runs on every merge to main: install dependencies, run lint and unit tests, build a signed iOS .ipa and Android .aab, and upload both to testers. Google Play has required new apps to publish as Android App Bundles with Play App Signing since August 2021. TestFlight accepts up to 10,000 external testers and each build expires after 90 days; the Play internal testing track takes up to 100 testers and is the fastest route to real devices.
Choosing the tools
| Tool | Fits | What it does |
|---|---|---|
| EAS Build + EAS Submit | Expo and React Native | Cloud builds; uploads the .ipa to App Store Connect and the .aab to a chosen Play track |
| Fastlane | Any stack | Open-source lanes for building, signing with match, and uploading to TestFlight and Play |
| Codemagic | Flutter, React Native, native | Hosted CI on Apple silicon Macs, configured in codemagic.yaml |
| GitHub Actions | Any stack | Hosted macOS runners that usually run Fastlane or the EAS CLI |