React Native CI/CD Pipeline with GitHub Actions: 4 Blueprints for 2026
Konrad Bachowski
Tech lead, HeyNeuron
React Native CI/CD Pipeline with GitHub Actions: Complete 2026 Guide
Manual builds killed a startup's App Store review deadline. A developer forgot to bump the build number, the iOS upload failed, and the launch slipped two days. That's the CI/CD argument in one sentence — when releases depend on individuals following checklists under pressure, they will eventually fail.
This guide sets up a production-grade React Native CI/CD pipeline using GitHub Actions and EAS Build: four workflow blueprints, a cost comparison across five build infrastructure options, ROI math for teams of different sizes, GDPR secrets management, and the four scenarios where CI/CD is the wrong investment right now.
Why CI/CD is Now Non-Negotiable for React Native Teams
According to DORA's 2024 State of DevOps Report (cited by 9cv9.com's 2026 DevOps statistics), elite engineering teams deploy 182 times more frequently than low performers. The mechanism isn't magic — it's automation that removes humans from the error-prone repetitive steps of the release process.
For React Native specifically, the stakes are higher than for web apps:
- iOS and Android have separate, complex signing requirements that must be correct every time
- The Apple App Store review process takes 1–3 days, meaning a failed upload wastes an entire review cycle
- Over-the-air (OTA) updates via EAS Update need to be deployed safely — a broken OTA bundle can break every installed app instantly
- Bitrise Mobile Insights 2025 reports that test flakiness grew from 10% in 2022 to 26% by mid-2025 — making automated quality gates in CI more critical, not less
The cost of not having CI/CD is hidden but real. A senior developer spending 45 minutes per release build — running bundle exec fastlane, typing signing passwords, watching Xcode Archive — at $75/hr costs $56.25 per release. With 3 releases per week across iOS and Android, that's $8,775/year in pure manual build time, before counting failed submissions and incident recovery.
According to ElectroIQ 2026, fully automated CI/CD pipelines reduce delivery times by 40% while simultaneously improving deployment stability.
Pipeline Architecture: Four Workflows, One Coherent System
The most common mistake teams make is writing a single monolithic workflow file that tries to do everything. The production approach uses four purpose-built workflows:
| Workflow | Trigger | Runs On | Purpose |
|---|---|---|---|
| PR Checks | Pull request opened/updated | GitHub-hosted (Linux) | Lint, TypeScript, Jest, bundle size |
| Preview Build | Push to develop |
GitHub-hosted (macOS) | Dev build for internal testers |
| Production Build | Tag v*.*.* push |
GitHub-hosted (macOS) | Release build + store submission |
| OTA Update | Manual dispatch / tag | GitHub-hosted (Linux) | EAS Update to production channel |
This separation means a broken test in a feature branch never blocks a hotfix OTA update. Each workflow can fail or succeed independently, and GitHub's environment protection rules add human approval gates before anything reaches the store.
Prerequisites
Before writing YAML, set up these accounts and tools:
Required accounts:
- GitHub (Free plan gives 2,000 included minutes/month; Pro gives 3,000)
- Expo account (EAS Build Free: 15 builds/platform/month; Starter: $9/month with 30 builds)
- Apple Developer Program ($99/year)
- Google Play Console ($25 one-time)
Required CLI tools:
npm install -g expo-cli eas-cli
eas login
eas build:configure # creates eas.json
Required GitHub Secrets (Settings → Secrets and variables → Actions):
EXPO_TOKEN # eas whoami --token, never commit this
APPLE_ID # your Apple Developer email
ASC_APP_ID # App Store Connect app ID (numeric)
GOOGLE_SERVICE_ACCOUNT # base64-encoded service account JSON
Blueprint 1: PR Checks Workflow
This workflow runs on every pull request. It must be fast (under 5 minutes) to give developers immediate feedback.
# .github/workflows/pr-checks.yml
name: PR Checks
on:
pull_request:
branches: [main, develop]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: TypeScript check
run: npx tsc --noEmit
- name: ESLint
run: npm run lint
- name: Jest tests
run: npm test -- --coverage --ci --passWithNoTests
- name: Bundle size check
run: |
npx react-native bundle --platform android --dev false \
--entry-file index.js --bundle-output /tmp/bundle.js
BUNDLE_SIZE=$(wc -c < /tmp/bundle.js)
echo "Bundle size: ${BUNDLE_SIZE} bytes"
if [ "$BUNDLE_SIZE" -gt 5000000 ]; then
echo "❌ Bundle exceeds 5MB threshold"
exit 1
fi
What this catches: TypeScript errors, lint violations, failing unit tests, and bundle size regressions — all before a single reviewer looks at the PR. The cache: 'npm' instruction alone saves 2–3 minutes per run by reusing the node_modules cache across runs.
Blueprint 2: Preview Build on Push to Develop
When code merges to develop, build a development client for internal testers. This gives QA a real binary within 15–20 minutes of a merge.
# .github/workflows/preview-build.yml
name: Preview Build
on:
push:
branches: [develop]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Setup EAS
uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Build preview
run: eas build --platform all --profile preview --non-interactive
- name: Post build URL to PR
run: |
echo "Preview build complete. Check EAS dashboard for download links."
The --profile preview flag in eas.json should point to an internal distribution build — one that bypasses the App Store and can be installed directly on registered test devices. This keeps QA from waiting for TestFlight propagation.
Blueprint 3: Production Build and Store Submission
This is the high-stakes workflow. It triggers only on version tags (e.g., v1.4.2), uses GitHub Environments for manual approval before submission, and handles both iOS and Android in parallel.
# .github/workflows/production.yml
name: Production Build & Submit
on:
push:
tags:
- 'v*.*.*'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
platform: [ios, android]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Build ${{ matrix.platform }}
run: eas build --platform ${{ matrix.platform }} --profile production --non-interactive
submit:
needs: build
runs-on: ubuntu-latest
environment: production # requires manual approval in GitHub Environments
strategy:
matrix:
platform: [ios, android]
steps:
- uses: actions/checkout@v4
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Submit ${{ matrix.platform }}
run: eas submit --platform ${{ matrix.platform }} --latest --non-interactive
The environment: production gate is critical. Without it, a bad commit could auto-submit to the App Store the moment someone pushes a version tag. With it, a designated reviewer must approve the submission step in GitHub's UI — the human checkpoint that prevents automated disasters.
Blueprint 4: OTA Updates with EAS Update
Over-the-air updates let you push JavaScript bundle fixes without going through store review. This workflow uses a manual trigger (workflow_dispatch) so the team consciously chooses when to ship an OTA.
# .github/workflows/ota-update.yml
name: OTA Update
on:
workflow_dispatch:
inputs:
message:
description: 'Update message for EAS dashboard'
required: true
default: 'Bug fix'
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Publish OTA update
run: |
eas update --channel production \
--message "${{ github.event.inputs.message }}" \
--non-interactive
OTA safety rules: Only JavaScript changes can be OTA'd. Native module additions, app.json config changes, or SDK upgrades require a full store build. Shipping a bundle with native API calls to an OTA build that lacks those native modules will crash the app on every device.
EAS Build vs Fastlane: Which Should You Use?
Teams migrating from Fastlane often ask whether to rewrite their lanes or switch to EAS. The answer depends on your complexity:
| Factor | EAS Build | Fastlane |
|---|---|---|
| Code signing | Managed automatically | Manual Matchfile configuration |
| Custom native build steps | Limited (EAS hooks) | Full Ruby scripting flexibility |
| Self-hosted option | EAS local builds | Full self-hosted control |
| Build minutes cost | EAS Free/Starter/Production tiers | GitHub-hosted runner costs only |
| Learning curve | Low (one CLI) | Medium (Ruby, lane syntax) |
| Best for | Expo-based or new projects | Legacy Bare RN with complex lanes |
For greenfield React Native projects using Expo, EAS Build with expo-github-action is the clear choice. For mature projects with 50+ Fastlane lanes, custom plugins, or enterprise MDM distribution, Fastlane remains the more powerful option.
Cost Breakdown: Five Build Infrastructure Options
A common mistake is assuming "GitHub Actions is free." It is — up to a point. Here's what infrastructure actually costs at different build volumes:
| Option | Monthly cost | Free minutes | iOS build cost | Best for |
|---|---|---|---|---|
| GitHub Free | $0 | 2,000 min/mo | ~$0.08/min macOS | Solo devs, < 25 builds/mo |
| GitHub Pro | $4/mo | 3,000 min/mo | ~$0.08/min macOS | Small teams |
| EAS Build Starter | $9/mo | 30 builds/platform | Flat rate | Expo teams |
| Self-hosted runner | $20–80/mo infra | Unlimited | Hardware cost only | High-volume teams |
| Bitrise | $0–$450/mo | 200 min/mo | ~0.04 credit/min | Larger mobile teams |
2026 pricing note: GitHub cut hosted runner prices by up to 39% in January 2026. A 16-core Linux runner now costs $0.042/minute — and macOS M1 runners dropped to $0.16/minute. For teams running 50–100 iOS builds per month, that's a meaningful reduction in infrastructure spend.
Break-even calculation for self-hosted:
If each iOS build takes 15 minutes at $0.16/minute, that's $2.40/build. A dedicated Mac mini M4 ($700, amortized over 36 months) costs $19.44/month. At that rate, you need to run 9 builds per month before self-hosted is cheaper than GitHub-hosted. Most teams crossing 15+ monthly builds should evaluate self-hosted.
When NOT to Set Up CI/CD
Automation has real setup costs. These scenarios are where CI/CD investment doesn't pay off yet:
-
Solo developer, sub-weekly releases. If you ship once a month and own the whole codebase, 30 minutes of manual work 12 times a year (6 hours total) costs less than a full CI/CD setup and maintenance burden.
-
Pre-MVP, unstable native module list. Every time you add a new native module, you may need to rebuild CI caching layers and update signing configurations. Set up CI after the native dependency list stabilizes, not before.
-
Team without a designated DevOps owner. A CI/CD pipeline needs someone who understands GitHub Secrets rotation, EAS token management, and signing certificate renewal. Without that person, broken pipelines sit unfixed for weeks — worse than the manual process they replaced.
-
App not yet on any store. The largest ROI from CI/CD comes from automating store submissions. If your app hasn't shipped to the App Store or Play Store yet, focus on getting the manual process right first, then automate it.
GDPR and Secrets Management for Compliant Pipelines
CI/CD pipelines handle sensitive data: API keys, signing certificates, service account JSON files. GDPR Article 5(1)(f) requires "appropriate security" for personal data processing infrastructure — and your pipeline is infrastructure.
Secrets hygiene checklist:
- [ ] Never commit secrets to version control. Use
git-secretsor GitHub's secret scanning, which automatically blocks pushes containing AWS keys, Google credentials, and other known patterns - [ ] Rotate secrets on team member departure. Revoke and regenerate
EXPO_TOKEN,APPLE_IDapp-specific passwords, and Google Service Account keys within 24 hours of any role change - [ ] Scope service account permissions. Google Play service accounts should have only "Release Manager" permission — not "Admin." Principle of least privilege applies to CI secrets too
- [ ] Use GitHub Environments for production secrets. Production secrets (store credentials) stored in an Environment rather than repo-level secrets can only be accessed by workflows explicitly referencing that Environment
- [ ] Audit secret access logs. GitHub's audit log (Organization → Audit log) captures when secrets were accessed. Review quarterly
EU data residency: If your app processes EU personal data and you're concerned about CI/CD pipeline data handling, GitHub Actions supports EU-hosted runners on GitHub Enterprise Cloud. For self-hosted, running runners in an EU AWS/GCP/Azure region satisfies data residency requirements. Standard GitHub-hosted runners run in US data centers — acceptable for most pipelines where code (not user data) flows through CI, but document this in your Article 30 Records of Processing Activities.
ROI Math: Is CI/CD Worth It?
For a 3-person team shipping to iOS and Android twice a week:
Manual baseline (annual cost):
- Build + upload time per release: 45 min × 2 platforms = 90 min
- Releases per year: 104
- Total annual build time: 156 hours
- At $75/hr developer time: $11,700/year
CI/CD setup and maintenance:
- Initial setup (one-time): 16 hours × $75/hr = $1,200
- Monthly maintenance: 2 hours × $75/hr = $150/month = $1,800/year
- GitHub Pro + EAS Starter: $4 + $9 = $13/month = $156/year
- Total annual CI/CD cost: $3,156
Annual savings: $8,544 — with the added benefit of consistent builds, automated testing, and no 2am manual submissions before an App Store deadline.
According to DORA 2024 data (via 9cv9.com), organizations with mature CI/CD achieve a 50% reduction in time-to-market — a metric that for mobile teams directly maps to competitive advantage in App Store ranking speed and user acquisition timing.
Frequently Asked Questions
How many GitHub Actions minutes does a React Native build use?
A typical iOS production build using expo/expo-github-action with EAS Build runs the GitHub workflow for 5–10 minutes (the actual compile happens on EAS servers, not GitHub runners). The Android build similarly runs 5–8 minutes of GitHub minutes. The macOS runner cost for iOS signing and submission adds $0.40–$0.80 per run.
Can I use GitHub Actions with bare React Native (non-Expo)?
Yes. Bare React Native projects use Fastlane lanes run by GitHub Actions. The workflow calls bundle exec fastlane ios beta or bundle exec fastlane android deploy — the YAML triggers remain the same, but the build tooling is Fastlane instead of EAS. Set up Ruby caching (actions/cache for vendor/bundle) to keep build times under 15 minutes.
How do I handle different environment variables for dev, staging, and production?
Use expo-env-info or react-native-config with .env.development, .env.staging, .env.production files. In GitHub Actions, store environment-specific values in GitHub Environments (not repo secrets) so each environment's variables are isolated. The workflow references ${{ vars.API_URL }} which resolves to the correct Environment's variable.
How long does a full production build take?
With EAS Build, the queue wait time varies by plan. EAS Free plan can queue for 5–30 minutes. EAS Starter (priority queue) typically starts within 2 minutes. Build time itself: iOS 12–22 minutes, Android 10–18 minutes. Total end-to-end including GitHub workflow overhead: 20–45 minutes from git push to a signed binary ready for store submission.
What happens if a production build fails in CI?
GitHub Actions marks the workflow as failed (red ✗), sends a notification to configured Slack/email channels, and — critically — the submit job that depends on build never runs. The App Store is never reached. This is the exact safety net CI/CD provides: failed builds gate downstream steps automatically.
Should I use EAS Update (OTA) for every bug fix?
No. OTA is appropriate for JavaScript-only changes: bug fixes, copy changes, API call updates, UI tweaks. It is not appropriate for native module additions, Expo SDK upgrades, permission changes, or anything touching ios/ or android/ directories. Shipping a native change via OTA will crash the app on devices that don't have the updated binary.
How do I rotate expired iOS distribution certificates in CI?
With EAS managed credentials, run eas credentials locally. EAS stores your Apple Developer credentials in its system and rotates certificates automatically when they expire — you don't touch Keychain Access. If using Fastlane Match, regenerate the certificate in your Match Git repo and update the MATCH_PASSWORD GitHub Secret.
How much does it cost to run CI/CD for a React Native app?
For a team of 2–3 developers shipping twice per week: GitHub Pro ($4/month) + EAS Build Starter ($9/month) = $13/month total. Self-hosted runners on a $40/month VPS eliminate GitHub minute costs. The full infrastructure runs under $20/month for most small teams — the ROI versus developer time saved is typically 10:1 or better in the first year.
Building Your React Native Pipeline: What to Do First
The 30-second version of this guide: start with Blueprint 1 (PR checks) only. Get TypeScript, lint, and Jest running on every pull request. That alone will catch 80% of regressions before they reach main. Add Blueprint 3 (production builds) only after you've shipped at least one release manually — you need to understand the manual process before automating it.
A pipeline that runs automatically is only trustworthy if the team understands what it does when it breaks. The four blueprints above are designed to fail loudly and clearly, so when something goes wrong in CI, the problem is obvious rather than buried in 3,000 lines of Xcode output.
If your team doesn't have the internal capacity to set this up and maintain it — and most product-focused teams shouldn't have to — HeyNeuron builds and maintains CI/CD infrastructure for React Native teams as part of our mobile development service. We own the pipeline so your developers own the product.
Contact us to review your current build and release process.
Additional reading from our React Native series:
- React Native app architecture and folder structure guide
- React Native performance optimization techniques
- React Native testing best practices: Jest, Detox, and Maestro
- How to deploy a React Native app with EAS and ASO
- Mobile app MVP cost breakdown 2026
- How to choose the right tech stack for your web app
- React Native app development company in Poland
Stay up to date with AI and automation
Subscribe to our newsletter to receive specific tips and tools once a week. Join over 2,000 subscribers.