Continuous Integration for React Native Apps with Fastlane and GitHub Actions

Continuous integration for React Native should do more than run npm test.
A useful pipeline protects every pull request, builds signed release artifacts
from clean commits, keeps secrets out of the repository, and makes app store
submission repeatable.
This guide covers a pragmatic CI/CD setup for modern React Native apps using GitHub Actions, EAS Workflows, EAS Build, EAS Submit, EAS Update, and fastlane. Use the parts that fit your project. Do not create three different release systems unless your team can operate all of them.
Quick Answer
For most React Native teams:
- Use GitHub Actions for pull request checks: install, typecheck, lint, unit tests, and lightweight static checks.
- Use EAS Build or EAS Workflows for signed iOS/Android builds when the app uses Expo modules or you want managed mobile build infrastructure.
- Use EAS Submit to upload app binaries to App Store Connect and Google Play when it matches your release process.
- Use EAS Update only for JavaScript and asset updates compatible with the installed native binary.
- Use fastlane when your team already has native lanes for signing, screenshots, metadata, TestFlight, Google Play tracks, or Firebase App Distribution.
- Store every signing key, API token, keystore, and service account credential in CI secrets or the provider's credential store.
If you are using an Instamobile React Native app, first review the Current React Native Stack and React Native App Release Checklist.
Recommended Pipeline Shape
A healthy mobile CI/CD setup has separate gates:
| Gate | Runs on | Purpose |
|---|---|---|
| PR checks | Pull requests | Catch TypeScript, lint, unit test, formatting, and dependency issues early. |
| Preview build | Labels, manual trigger, or selected branches | Give QA a signed build from a known commit. |
| Release candidate | Main/release branch | Build store-ready Android and iOS artifacts. |
| Submission | Manual approval or release tag | Upload to Google Play/App Store Connect. |
| OTA update | Carefully selected commits | Publish compatible JS/assets only. |
Do not submit to stores from every push to main. App store release should be a
deliberate action with review notes, release notes, and rollback ownership.
Current React Native Baseline
For current Instamobile React Native apps, use the app package and the Current React Native Stack as the source of truth. In practice, CI should respect:
- TypeScript-first source;
- Yarn 4 through Corepack;
- the Node version requested by the app;
- the React Native and Expo module versions declared by the app;
- the Android SDK and iOS deployment targets declared by the native projects;
- Firebase Functions runtime requirements when backend functions are included.
The app package is still the source of truth. Check package.json, yarn.lock,
ios/Podfile, android/build.gradle, android/app/build.gradle, and the app
README before pinning CI images or commands.
GitHub Actions for PR Checks
Start with a small workflow that all pull requests must pass.
name: React Native Checks
on:
pull_request:
push:
branches:
- main
jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: yarn
- name: Enable Corepack
run: corepack enable
- name: Install dependencies
run: corepack yarn install --immutable
- name: Typecheck
run: corepack yarn typecheck
- name: Run tests
run: corepack yarn test --watch=false
Adjust script names to the app package. Some apps use lint, test, doctor,
or verify; others only expose a focused set of scripts. Do not invent CI
commands that the project does not have.
Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount 🔥
Get the Mega BundleAdd Expo/EAS Checks
For apps that use Expo modules or EAS, add Expo validation after dependency installation:
- name: Expo doctor
run: corepack yarn expo-doctor
If the app script is named differently, call that script instead:
corepack yarn doctor
Use expo-doctor as a compatibility signal, not as a replacement for running
release builds on real devices.
Build With EAS
EAS Build is usually the cleanest path for React Native apps that use Expo modules, config plugins, EAS credentials, or cloud-managed signing.
Typical local setup:
npm install -g eas-cli
eas login
eas build:configure
Example eas.json shape:
{
"build": {
"preview": {
"distribution": "internal",
"channel": "preview"
},
"production": {
"channel": "production",
"android": {
"buildType": "app-bundle"
}
}
},
"submit": {
"production": {}
}
}
Build commands:
eas build --profile preview --platform all
eas build --profile production --platform all
Use preview builds for QA and production builds for app store artifacts. Keep profiles explicit so an internal test build cannot be confused with a store release.
Use EAS Workflows for Mobile Build Automation
EAS Workflows can run mobile-specific jobs on EAS infrastructure, including build, submit, update, and Maestro jobs. This is useful when you want mobile CI without maintaining macOS runners, Android SDK setup, or Xcode images yourself.
Use EAS Workflows for:
- signed Android and iOS builds;
- app store submission jobs;
- OTA update jobs;
- Maestro end-to-end smoke tests;
- manual release workflows;
- GitHub-triggered build jobs.
Keep GitHub Actions for generic repository checks if that is already your team standard, then delegate mobile artifact work to EAS.
Submit Builds With EAS Submit
EAS Submit uploads valid Android App Bundles and iOS IPAs to the store distribution pipelines.
eas submit --platform android
eas submit --platform ios
Build and submit in one flow:
eas build --platform all --profile production --auto-submit
Important release notes:
- Android submissions go to the Google Play track you configure.
- iOS submissions upload to App Store Connect and appear in TestFlight after processing.
- TestFlight upload is not the same as App Store production release.
- First-time Google Play API submissions may require manual Play Console setup first.
- Store metadata, privacy, review notes, and screenshots still need human review.
Publish OTA Updates Carefully
EAS Update is useful for compatible JavaScript, styling, and asset changes. It is not a replacement for native builds.
Setup:
eas update:configure
Publish a production update:
eas update --channel production --message "Fix checkout button state" --environment production
Use the environment flag when your EAS setup separates preview, staging, and production variables. Check the current EAS Update docs before automating this step, because update requirements can change with Expo SDK releases.
Do not use OTA for:
- native dependency changes;
- permission changes;
- entitlement changes;
- app icon or splash changes;
- React Native upgrades;
- SDK upgrades;
- payment or push native configuration changes.
For OTA strategy and CodePush migration context, read CodePush in React Native.
Where fastlane Still Fits
fastlane remains valuable for teams with mature native release lanes.
Good fastlane use cases:
- custom iOS signing and Match;
- uploading to TestFlight;
- uploading Android App Bundles to Play tracks;
- generating screenshots;
- managing metadata;
- distributing QA builds through Firebase App Distribution;
- integrating with existing native release scripts.
Android lane example:
default_platform(:android)
platform :android do
lane :build_release do
gradle(
task: "bundle",
build_type: "Release",
project_dir: "android"
)
end
end
iOS lane example:
default_platform(:ios)
platform :ios do
lane :build_release do
setup_ci
app_store_connect_api_key(
key_id: ENV["APP_STORE_CONNECT_KEY_ID"],
issuer_id: ENV["APP_STORE_CONNECT_ISSUER_ID"],
key_content: ENV["APP_STORE_CONNECT_KEY_CONTENT"]
)
build_app(
scheme: "MyApp",
export_method: "app-store",
output_directory: "build",
output_name: "MyApp.ipa"
)
end
end
If you choose fastlane, keep the lane names boring and explicit:
build_android_release, submit_android_internal, build_ios_release,
upload_ios_testflight. Ambiguous names like deploy become risky over time.
Secrets and Credentials Checklist
Never commit these:
- Android upload keystore;
- keystore passwords;
- Google Play service account JSON;
- App Store Connect API key private key;
- provisioning profiles or certificates unless stored intentionally through a secure signing system;
- Firebase service account files;
- Expo access tokens;
- Stripe, Twilio, OpenAI, or other provider secrets;
.envfiles containing private values.
Store secrets in:
- GitHub Actions secrets;
- EAS secrets/environment variables;
- fastlane Match private storage;
- cloud secret managers;
- CI provider secret stores.
Be careful with pull requests from forks. Do not expose signing or submission secrets to untrusted PR workflows.
GitHub Actions + EAS Example
This pattern keeps PR checks in GitHub Actions and uses EAS only for release operations.
name: React Native Release Candidate
on:
workflow_dispatch:
inputs:
profile:
description: EAS build profile
required: true
default: preview
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: yarn
- name: Enable Corepack
run: corepack enable
- name: Install dependencies
run: corepack yarn install --immutable
- name: Typecheck
run: corepack yarn typecheck
- name: Setup Expo and EAS
uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Build with EAS
run: eas build --profile "${{ inputs.profile }}" --platform all --non-interactive
For production submission, use a separate manual workflow with an approval step or a protected environment. Keep production submission out of normal PR checks.
Release Gates Before Store Submission
Before CI uploads to App Store Connect or Google Play:
-
corepack yarn install --immutablepasses. - TypeScript passes.
- Unit tests pass.
- Native config points to production app identifiers.
- Firebase config files are production-ready.
- Firestore/Storage rules and Functions are deployed where needed.
- App Check, push, payments, maps, media upload, and auth are tested where included.
- Android App Bundle is signed and targets the required API level.
- iOS archive uses the production bundle ID and signing team.
- Store metadata, privacy forms, screenshots, and review notes are ready.
- Rollback/hotfix owner is assigned.
CI can enforce some of these. The rest should live in the release checklist because they require product and account context.
Common CI Failures
| Failure | Likely cause |
|---|---|
| Works locally but fails in CI install | Corepack/Yarn version mismatch or lockfile drift. |
| Android build cannot sign | Missing keystore secret, wrong alias, or wrong Gradle property names. |
| iOS build fails on CI only | Wrong Xcode image, missing signing identity, or provisioning mismatch. |
| EAS Update reaches wrong users | Channel/profile mismatch or missing runtime version discipline. |
| Store upload works but review fails | Privacy, app access, metadata, screenshots, or policy forms incomplete. |
| PR from fork cannot access secrets | Expected security behavior; do not weaken it for signing workflows. |
Useful Links
- Current React Native Stack
- React Native App Release Checklist
- EAS Submit documentation
- EAS Update documentation
- EAS Workflows documentation
- expo/expo-github-action
- fastlane for React Native
- GitHub Actions dependency caching
Looking for a custom mobile application?
Our team of expert mobile developers can help you build a custom mobile app that meets your specific needs.
Get in TouchFAQ
Should React Native apps use GitHub Actions or EAS Workflows?
Use GitHub Actions for general repository checks when your team already works in GitHub. Use EAS Workflows for mobile-specific build, submit, update, and E2E jobs when you want Expo-managed mobile infrastructure.
Do I still need fastlane if I use EAS?
Not always. EAS can handle build and submit workflows for many teams. Keep fastlane when you already rely on native lanes for signing, metadata, screenshots, TestFlight, Google Play tracks, or Firebase App Distribution.
Can CI publish OTA updates on every merge?
Technically yes, but it is risky. OTA updates should still respect runtime compatibility, QA, release notes, monitoring, and rollback rules.
Should store submission be automatic?
Store upload can be automated, but production release should usually require a manual approval gate. App stores involve policy, metadata, privacy, and support readiness, not only a build artifact.
Conclusion
React Native CI/CD works best when each tool has a clear job. Let GitHub Actions protect pull requests, let EAS or fastlane build signed mobile artifacts, keep store submission behind deliberate release gates, and reserve OTA updates for compatible non-native fixes.
The goal is not maximum automation. The goal is a release process that produces the same trusted artifact from the same commit, keeps secrets safe, and gives your team a fast path from issue to verified fix.