◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Dev Tools
⬡ Dev Tools/2026-03-14Advanced

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.

Rork585EAS9Expo219CI/CD8OTA7GitHub Actions5

✦ Premium Article

Why I moved six apps to EAS — and what broke first

Through the first months of 2026 I was pushing v2.0.0 and v2.1.0 updates across six apps in parallel — most of them wallpaper apps I have been running since going independent in app development back in 2014. Archiving each one in Xcode, uploading to App Store Connect, exporting AABs for Play Console: doing that by hand for six apps swallowed the better part of two days per release wave. And whenever a small bug surfaced afterwards, the whole cycle started over.

Expo Application Services (EAS) is how I got that time back. It builds iOS and Android binaries in the cloud, ships JavaScript-only fixes over the air, and plugs into CI/CD — no local Xcode or Android Studio required, which also means you can build iOS apps without owning a Mac.

One clarification before we start, because the product naming trips people up: since February 2026, Rork generates Expo (React Native) apps for both iOS and Android, while Rork Max is a separate product that generates native Swift apps and compiles them on a cloud Mac fleet — it does not use EAS at all. Everything in this article applies to the Expo (React Native) projects that Rork produces.

What follows is the setup I actually run for my six apps, from first install to production checklist.


Setting up EAS — from the CLI to eas.json

Step 1: Install EAS CLI Globally

npm install -g eas-cli

Verify installation:

eas --version

Step 2: Authenticate with Expo Account

eas login

You'll be prompted to open a browser and log in to your Expo account. If you don't have one, sign up for free at expo.dev.

ℹ️
**Pro Tip**: For CI/CD environments (GitHub Actions, GitLab CI), generate an API token at [expo.dev/settings/access-tokens](https://expo.dev/settings/access-tokens) and store it as the `EXPO_TOKEN` environment variable. This enables passwordless authentication across all pipelines.

Step 3: Initialize EAS Build Configuration

eas build:configure

This command creates an eas.json configuration file in your project root. Below is a comprehensive example with development, preview, and production profiles.

Complete eas.json Configuration

{
  "cli": {
    "version": ">= 5.0.0"
  },
  "build": {
    "development": {
      "distribution": "internal",
      "channel": "development",
      "ios": {
        "buildType": "development",
        "enterpriseProvisioning": "universal-adhoc"
      },
      "android": {
        "buildType": "development",
        "gradleCommand": ":app:assembleDebug"
      }
    },
    "preview": {
      "distribution": "internal",
      "channel": "preview",
      "ios": {
        "buildType": "ad-hoc",
        "provisioning": {
          "teamId": "YOUR_APPLE_TEAM_ID"
        }
      },
      "android": {
        "buildType": "apk",
        "gradleCommand": ":app:assembleRelease"
      }
    },
    "production": {
      "distribution": "store",
      "channel": "production",
      "ios": {
        "buildType": "app-store",
        "provisioning": {
          "teamId": "YOUR_APPLE_TEAM_ID"
        }
      },
      "android": {
        "buildType": "aab",
        "gradleCommand": ":app:bundleRelease"
      }
    }
  },
  "submit": {
    "production": {
      "ios": {
        "appleId": "your-email@example.com",
        "ascAppId": "1234567890",
        "appleTeamId": "YOUR_APPLE_TEAM_ID"
      },
      "android": {
        "serviceAccount": "path/to/service-account.json",
        "track": "production"
      }
    }
  }
}

Profile Breakdown

  • development: For local testing. Internal distribution via Expo Go
  • preview: For QA teams. Builds can be shared via QR code or internal testing tracks
  • production: For App Store / Google Play releases. Generates AAB (Android App Bundle) and App Store-ready iOS builds

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Working configuration files and step-by-step setup for EAS Build, EAS Update, and GitHub Actions, drawn from running six apps in parallel
✦How to decide when the free tier's 30-builds-per-month quota stops being enough, with real queue-time observations
✦A same-day OTA hotfix walkthrough and a rollback design you can copy
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
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 →

Related Articles

⬡ Dev Tools2026-09-04
EAS secret visibility does not keep a value out of your app — deciding prefix and visibility separately
The EXPO_PUBLIC_ prefix decides what ships inside your app; EAS visibility decides who can read it. Why stacking them blanks a value on OTA updates, and how to check your build.
⬡ Dev Tools2026-04-21
Rork × Fastlane × EAS Release Automation Guide — Ship Screenshots, Metadata, and TestFlight/Play Console Builds With One Command
A production-ready implementation guide for automating Rork app releases with Fastlane and EAS. Generate screenshots, sync store metadata, and ship to TestFlight and Google Play with a single command.
⬡ Dev Tools2026-10-15
When EXPO_PUBLIC_ Values Read Fine in Dev but Come Back undefined in Production: Telling the Spellings Apart
The API URL reads fine while developing and turns undefined once the app is built. The cause was how process.env was written. I lined up babel-preset-expo's output for dev and production and tabulated which spellings get replaced and which are left behind.