RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-03-21Intermediate

Setting Up CI/CD for Rork Apps with GitHub Actions and EAS Build

Learn how to build a complete CI/CD pipeline for your Rork app using GitHub Actions and EAS Build. From automated testing on every pull request to hands-free TestFlight deployment, this guide walks you through the entire setup.

Rork515GitHub Actions5EAS Build14CI/CD7Expo149TestFlight11Automation8DevOps

Why Your Rork App Needs a CI/CD Pipeline

Rork makes building mobile apps incredibly fast — just describe what you want, and you've got a working app. But as your app grows and you start iterating on features, manually building, testing, and distributing each version quickly becomes a bottleneck.

A CI/CD (Continuous Integration / Continuous Delivery) pipeline automates the entire workflow: push your code, and everything from running tests to building binaries to shipping them to TestFlight happens automatically. Since Rork generates React Native + Expo projects, GitHub Actions paired with EAS Build is a natural fit.


Prerequisites

Before diving in, make sure you have the following ready:

  • A Rork account (Standard or Rork Max)
  • A GitHub account with your Rork project pushed to a repository
  • An Expo account (required for EAS Build)
  • Node.js 18+ installed locally
  • An Apple Developer Program membership (if you plan to deploy to TestFlight)

Start by exporting your Rork project using the built-in Export feature. This gives you a standard React Native + Expo project structure that you can push straight to GitHub.


Configuring EAS Build

What Is EAS?

EAS (Expo Application Services) is a cloud build and distribution platform from the Expo team. It lets you build native iOS and Android binaries without needing Xcode or Android Studio on your local machine.

Initial Setup

From the root of your exported Rork project, install and configure the EAS CLI:

# Install EAS CLI globally
npm install -g eas-cli
 
# Log in to your Expo account
eas login
 
# Initialize EAS in your project
eas build:configure

Running eas build:configure generates an eas.json file. Edit it to define three build profiles — development, preview, and production:

{
  "cli": {
    "version": ">= 14.0.0"
  },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "ios": {
        "simulator": true
      }
    },
    "preview": {
      "distribution": "internal",
      "ios": {
        "resourceClass": "m-medium"
      }
    },
    "production": {
      "ios": {
        "resourceClass": "m-medium"
      },
      "android": {
        "buildType": "app-bundle"
      }
    }
  },
  "submit": {
    "production": {
      "ios": {
        "appleId": "your-apple-id@example.com",
        "ascAppId": "your-app-store-connect-app-id",
        "appleTeamId": "YOUR_TEAM_ID"
      }
    }
  }
}

Managing Credentials

EAS Build can automatically manage your iOS certificates and provisioning profiles in the cloud. On your first build, it walks you through the setup interactively, or you can pre-configure credentials with eas credentials.

For Android, EAS auto-generates a keystore. Make sure to back up your production keystore — losing it means you won't be able to push updates to your existing app listing.


Building GitHub Actions Workflows

Adding Repository Secrets

To let GitHub Actions trigger EAS builds, you need to store your Expo access token as a repository secret:

  1. Generate an access token from your expo.dev account settings
  2. Go to your GitHub repo → Settings → Secrets and variables → Actions
  3. Add a new secret named EXPO_TOKEN with your token

Automated Testing on Pull Requests

Create a workflow that runs your test suite whenever a pull request targets the main branch:

# .github/workflows/test.yml
name: Test
 
on:
  pull_request:
    branches: [main]
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
 
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
 
      - run: npm ci
 
      - name: TypeScript type check
        run: npx tsc --noEmit
 
      - name: Lint
        run: npx eslint . --max-warnings 0
 
      - name: Unit tests
        run: npx jest --coverage --ci

This workflow performs three checks: TypeScript type verification, ESLint rule enforcement, and Jest unit test execution. If any of them fail, the PR gets flagged before anyone reviews it.

Build and Deploy on Merge

Once code lands on main, this workflow automatically kicks off an EAS build and submits it to TestFlight:

# .github/workflows/build-and-deploy.yml
name: Build and Deploy
 
on:
  push:
    branches: [main]
 
jobs:
  build-ios:
    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: Build iOS (Production)
        run: eas build --platform ios --profile production --non-interactive
 
      - name: Submit to TestFlight
        run: eas submit --platform ios --latest --non-interactive
 
  build-android:
    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: Build Android (Production)
        run: eas build --platform android --profile production --non-interactive

The iOS and Android builds run in parallel, so you're not waiting twice as long. The eas submit command handles the TestFlight upload automatically once the iOS build completes.


Preview Builds for Pull Requests

When working with a team, shipping a preview build for each pull request is a game changer. Reviewers can install the build on a real device and test the changes before merging.

# .github/workflows/preview.yml
name: Preview Build
 
on:
  pull_request:
    branches: [main]
    types: [opened, synchronize]
 
jobs:
  preview:
    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: Build preview
        run: eas build --platform ios --profile preview --non-interactive
 
      - name: Comment build link on PR
        uses: expo/expo-github-action/preview-comment@v8
        with:
          project: your-project-slug

The workflow automatically comments a build link on the PR, so reviewers can tap it and install the preview build directly — no extra coordination needed.


Instant Hotfixes with EAS Update

For JavaScript-only changes that don't touch native code, EAS Update lets you push over-the-air (OTA) updates directly to users — no App Store review required.

# .github/workflows/update.yml
name: OTA Update
 
on:
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'assets/**'
      - 'app.json'
 
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 --branch production --message "${{ github.event.head_commit.message }}"

The paths filter ensures OTA updates only trigger when JavaScript or asset files change. When native dependencies are updated, a full build is still needed — that's why keeping these workflows separate matters.


Automating Semantic Versioning

Manually bumping version numbers in app.json is tedious and error-prone. You can automate it based on commit message conventions:

# .github/workflows/version-bump.yml
name: Version Bump
 
on:
  push:
    branches: [main]
 
jobs:
  bump:
    runs-on: ubuntu-latest
    if: "!contains(github.event.head_commit.message, 'chore: bump version')"
    steps:
      - uses: actions/checkout@v4
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
 
      - uses: actions/setup-node@v4
        with:
          node-version: 20
 
      - name: Determine version bump type
        id: bump
        run: |
          MSG="${{ github.event.head_commit.message }}"
          if echo "$MSG" | grep -qi "breaking\|major"; then
            echo "type=major" >> $GITHUB_OUTPUT
          elif echo "$MSG" | grep -qi "feat\|feature"; then
            echo "type=minor" >> $GITHUB_OUTPUT
          else
            echo "type=patch" >> $GITHUB_OUTPUT
          fi
 
      - name: Bump version in app.json
        run: npx expo-version-bump ${{ steps.bump.outputs.type }}

Commit messages containing feat: trigger a minor version bump, breaking: triggers a major bump, and everything else gets a patch increment.


Optimizing Build Times and Costs

Here are a few practical tips to keep your CI/CD pipeline fast and cost-effective.

Leverage npm caching. The cache: npm option in actions/setup-node dramatically speeds up dependency installation. What takes minutes on the first run drops to seconds on subsequent runs.

Choose the right EAS resource class. Setting resourceClass to m-medium or higher in eas.json gives you a faster build machine. Free-tier accounts are limited to m-small, but paid plans unlock m-large for significantly shorter build times.

Use conditional builds to save credits. Running a full native build on every push burns through EAS build credits fast. Use paths filters and if conditions to trigger full builds only when native dependencies change, and rely on OTA updates for JavaScript-only fixes.


Troubleshooting Common Issues

Build Failures

Check the EAS build logs via eas build:list or the expo.dev dashboard. The most common culprit is a version mismatch between the Expo SDK and a native dependency. For projects generated by Rork, the dependency tree is generally consistent, but if you've added packages manually, run npx expo-doctor to check compatibility.

Certificate Errors

If your iOS build fails with a signing error, run eas credentials to inspect the state of your certificates. EAS can auto-regenerate expired certificates, but if your Apple Developer account's App Store Connect API key has expired, you'll need to refresh it manually.

GitHub Actions Timeouts

When the EAS build queue is busy, builds can exceed GitHub Actions' default timeout of 6 hours. Set timeout-minutes: 120 on your job and consider using EAS webhooks to get notified when the build finishes instead of waiting in the Actions runner.


Wrapping Up

Adding a CI/CD pipeline to your Rork app with GitHub Actions and EAS Build transforms how you ship software. Instead of juggling manual builds and hoping nothing breaks, you get automated tests on every PR, hands-free builds and TestFlight delivery on merge, and instant OTA updates for quick fixes.

Start small — add the test workflow first and get comfortable with the flow. Then layer on the build and deploy workflows as your app matures. Once the pipeline is in place, you can focus on what matters most: building a great app.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-03-14
Moving Six Apps to EAS CI/CD — EAS Build, OTA Updates, and GitHub Actions in Practice
How I moved the build and release pipeline for six indie apps to Expo Application Services: EAS Build for iOS and Android, OTA updates with EAS Update, GitHub Actions integration, and honest notes on free-tier limits.
Dev Tools2026-05-27
Killing the Recurring iOS Missing Compliance Warning in Rork with One Info.plist Key
Walks through why every Rork-built iOS upload shows a yellow Missing Compliance flag on TestFlight, and how a single ITSAppUsesNonExemptEncryption key in your app.json removes it for good. Written from the perspective of an indie developer shipping six wallpaper apps in parallel.
Dev Tools2026-05-21
Rork iOS App Rejected with ITMS-90683 on TestFlight — How to Fix Missing Purpose Strings via app.json
If your Rork-built iOS app passes upload but gets an email titled ITMS-90683: Missing Purpose String in Info.plist, this guide walks through the real cause and the permanent fix via app.json, based on 12 years of shipping personal iOS apps with the same problem appearing across new SDK updates.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →