Automating a React Native release means more than running a build command on a server. This guide shows how to choose between Expo Application Services, GitHub Actions, and native build runners; estimate CI/CD cost with repeatable inputs; protect signing credentials; and create dependable pull request, staging, and production workflows for iOS and Android.
Overview
A practical React Native CI/CD system should make the path from code change to installable app predictable. It should validate pull requests, produce reviewable builds, keep environment values separated, and make store releases auditable. The best setup is not necessarily the one with the most automation. It is the one that matches your team’s native-module requirements, compliance needs, release frequency, and comfort with build infrastructure.
Most teams combine several layers:
- Source control and workflow orchestration: GitHub Actions or another CI provider starts jobs when a pull request, tag, or release event occurs.
- JavaScript and native validation: linting, type checking, unit tests, integration tests, and platform-specific checks catch problems before distribution.
- Build infrastructure: Expo Application Services (EAS), macOS runners, Android runners, or self-managed machines compile the app.
- Credential management: signing certificates, provisioning profiles, Android keystores, API tokens, and store credentials are stored outside the repository.
- Distribution: preview builds go to reviewers, staging builds go to internal testers, and production builds are submitted through a controlled release step.
Keep the workflow’s responsibilities separate. A pull request should answer “is this change safe to merge?” A staging workflow should answer “can testers validate this version?” A production workflow should answer “is this exact artifact approved for release?” Mixing these purposes makes failures harder to diagnose and increases the chance of releasing an unreviewed build.
For decisions about native modules, Expo compatibility, and the New Architecture, review the React Native Native Module Compatibility Guide. Your navigation, UI, and backend choices can also affect build configuration, so keep those dependencies visible when designing the pipeline.
How to estimate
Estimate CI/CD cost and effort using workload rather than a provider’s headline plan. The basic monthly build estimate is:
Monthly build minutes = builds per month × average billed minutes per build
Then separate build minutes by workflow:
- Pull request builds: number of pull requests × builds per pull request × average duration.
- Preview builds: number of preview builds × average duration.
- Staging builds: staging releases per month × average duration.
- Production builds: production releases per month × number of platform builds × average duration.
Do not estimate only the successful builds. Add retries caused by transient runner failures, dependency installation errors, expired credentials, and configuration changes. A simple planning assumption is to add a retry allowance to your expected build volume, then replace that assumption with observed data after the first few release cycles.
Also estimate operational effort. Record the time spent maintaining workflow files, updating Node, React Native, Expo, Xcode, Android Gradle, and JavaScript dependencies, rotating credentials, investigating failed builds, and supporting store submissions. A hosted service may reduce machine maintenance while introducing usage charges or platform-specific configuration. Self-managed runners may provide more control but require patching, access management, caching, and capacity planning.
Compare options using the same inputs:
| Option | Best fit | Cost inputs to track | Questions to ask |
|---|---|---|---|
| Expo Application Services | Expo-based teams that want hosted builds and a managed mobile release path | Build volume, platform mix, update and submission usage, team plan | Which credentials are managed, how are profiles separated, and how are build artifacts retained? |
| GitHub Actions with hosted runners | Teams that want CI orchestration close to source control | Workflow minutes, runner operating systems, artifact storage, cache usage | Are macOS jobs available for the required workflow, and what happens when jobs queue or fail? |
| Native hosted runners | Projects with custom Xcode, Gradle, or native-module requirements | Machine time, storage, concurrency, macOS availability, maintenance time | Can the runner reproduce local builds, and who owns toolchain upgrades? |
| Self-managed runners | Teams needing network control, custom hardware, or predictable internal access | Hardware, hosting, patching, monitoring, administration, backup | How are runners isolated, updated, and removed if compromised? |
Provider pricing, included minutes, storage limits, and platform availability change. Use the provider’s current documentation and your own build logs before making a purchasing decision. Treat any estimate as a range until you have measured real workflow duration.
Inputs and assumptions
Create a small CI/CD worksheet before selecting a platform. Include these inputs:
- Number of developers and repositories
- Pull requests per week and expected validation builds per pull request
- Preview, staging, and production build frequency
- iOS and Android build duration measured separately
- Expected retry rate and manual rerun frequency
- Required concurrency during release periods
- Whether builds use managed Expo workflows or custom native projects
- Retention requirements for logs, source maps, and installable artifacts
- Required secrets, certificates, provisioning profiles, and store accounts
- Time available for maintaining runners and upgrading the toolchain
Define environments explicitly. A common model is development for local work, preview for a branch or pull request, staging for release-candidate testing, and production for the store-approved artifact. Each environment should have a documented application identifier, API base URL, feature flags, update channel or distribution target, and signing policy.
Never place secrets in committed environment files or print them in build logs. Store secret values in the CI provider or build service’s encrypted secret store, restrict access by environment, and use separate credentials where the platform supports them. Environment variables are configuration, not a substitute for access control. Review the React Native Mobile App Security Checklist before finalizing deep links, storage, and dependency handling.
Build reproducibility is another important assumption. Pin or deliberately constrain Node and package-manager versions, commit the lockfile, document the Java and Android toolchain expectations, and record the Xcode version used for iOS builds. When a toolchain changes, update it in a controlled branch and run the full test and distribution path rather than changing the production runner without verification.
Worked examples
Pull request workflow
Use pull requests for fast feedback. Install dependencies from the lockfile, run formatting checks, linting, type checking, unit tests, and any lightweight integration tests. Build a preview artifact only when native configuration or user-interface review requires it; otherwise, a JavaScript and test-only gate may be faster and cheaper.
on pull_request:
install dependencies from lockfile
run lint and typecheck
run unit and integration tests
if native files changed:
create preview iOS and Android builds
upload logs and test results
block merge on required failuresUse path filters carefully. A change to native configuration, app permissions, assets, navigation, or a dependency with native code should trigger more validation than a documentation-only change. Test gates should be required for protected branches, while optional preview builds can remain available for reviewers.
Staging workflow
Start staging from a protected branch or an approved release candidate. Inject staging-only endpoints and feature flags, create both platform artifacts, and distribute them to the intended internal testers. Record the commit SHA, version name, build number, environment, and toolchain versions with the artifact.
on release-candidate approval:
verify clean working tree and lockfile
run full test suite
create signed staging builds
publish to internal distribution
attach commit SHA and release notes
collect tester feedback and crash reports
require approval before production promotionTest more than installation. Include login, push notifications, deep links, payments if relevant, offline behavior, upgrades from the previous version, accessibility checks, and localized flows. The React Native Accessibility Testing Guide and internationalization guide can help turn these areas into explicit release checks.
Production workflow
Make production releases tag-driven or approval-driven. The workflow should build from a known commit, verify versioning, run release gates, sign with production credentials, archive the artifacts, and submit only after a human or policy-based approval.
on approved version tag:
verify tag, branch, version, and build numbers
run release test suite
build signed iOS and Android artifacts
archive checksums, logs, and metadata
submit to configured store channels
record submission identifiers
monitor rollout and document rollback stepsDo not rebuild after approval unless the source, dependencies, or configuration changed intentionally. The artifact tested in staging should be traceable to the artifact submitted for production. Configure crash reporting and monitoring before release, and connect errors to the version and build number so a failed rollout can be investigated quickly.
When to recalculate
Recalculate the workflow estimate whenever an input changes, not only when a bill arrives. Review it after a release-frequency increase, a new platform target, a migration from Expo-managed builds to custom native runners, a change in test coverage, or the addition of a second application or brand.
Refresh the estimate when build durations rise. Measure queue time, runner time, dependency-install time, native compilation time, artifact upload time, and retry frequency separately. A slow build may be caused by an oversized cache, uncached dependencies, a larger test suite, a native-module change, or a provider capacity issue. Optimize the largest measured component first rather than adding runners immediately.
Revisit the pipeline before each annual mobile OS and toolchain cycle, and after updates to Node, React Native, Expo, Xcode, Android Gradle, Java, or critical native dependencies. Confirm that signing credentials remain valid, store access still works, and the current build service supports the required versions. Also review build-minute pricing, runner rates, storage allowances, and credential procedures directly with each provider because these inputs can change.
Use this release-readiness checklist:
- Pull request checks pass on the intended Node and package-manager versions.
- iOS and Android builds complete from a clean environment.
- Preview and staging configurations use the correct endpoints and feature flags.
- Signing credentials are stored securely and tested without exposing their values.
- Version names, build numbers, bundle identifiers, and application identifiers are correct.
- Automated tests cover the highest-risk flows, with manual checks for device-specific behavior.
- Accessibility, localization, deep links, permissions, and upgrade paths have been reviewed.
- Crash reporting, analytics where appropriate, logs, and source-map handling are configured.
- The production artifact is traceable to an approved commit and release record.
- A rollback, staged rollout, or hotfix procedure is documented and understood.
Finally, keep the pipeline documentation beside the code. Include the commands for local reproduction, the purpose of each environment, the location of secrets, approval ownership, and the procedure for rotating credentials. A React Native CI/CD system becomes dependable when its assumptions are visible, its artifacts are traceable, and its costs are recalculated from measured usage rather than guesswork.