●TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13●OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude Code●SIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App Store●MAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessage●NATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core ML●SEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round●TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13●OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude Code●SIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App Store●MAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessage●NATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core ML●SEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
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.
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.
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.
You'll need an Apple Developer Account to build for iOS. Sign up at developer.apple.com and enroll in the Apple Developer Program ($99/year).
Step 1: Configure iOS Credentials
eas credentials
This interactive command securely stores:
Apple ID email
App-specific password (recommended over account password)
Development and distribution certificates
Provisioning profiles
ℹ️
**Security First**: Never commit credentials to version control. EAS encrypts and manages all credentials server-side. For CI/CD, use `EXPO_TOKEN` instead of your Apple credentials.
Step 2: Create Your First iOS Build
eas build --platform ios --profile production
EAS queues the build and displays a build ID. Monitor progress:
eas build --status
Upon completion, you'll receive a .ipa file ready for TestFlight submission.
Step 3: Submit to TestFlight
eas submit --platform ios --profile production
The app automatically uploads to App Store Connect and becomes available to TestFlight internal testers within minutes.
EAS Update — shipping fixes without waiting for review
What OTA Updates Can Change
EAS Update distributes changes to JavaScript code and static assets without requiring new app store submissions.
Supported Updates:
React Native / Rork business logic
UI components and screens
API calling logic
StyleSheet and CSS-in-JS styles
Image and font assets
Not Supported:
New native modules
Permission changes
SDK version upgrades
Compiled native code
Deploy an OTA Update
eas update --branch production --message "Critical fix: payment processing crash"
This command:
Builds the JavaScript bundle
Uploads to EAS servers
Immediately distributes to all users on the production branch
Detailed Update with Metadata
eas update --branch production \ --message "v1.2.1: Improved dashboard performance" \ --metadata "{\"environment\": \"production\", \"severity\": \"high\"}"
Multi-Branch Release Strategy
# Canary release to 10% of userseas update --branch production \ --message "Experimental: new checkout flow" \ --percent 10# Promote to 50% after monitoringeas update --branch production \ --message "Expanding rollout to 50%" \ --percent 50# Full rollouteas update --branch production \ --message "Complete rollout of new checkout" \ --percent 100
Rollback to Previous Release
# View update historyeas update --list# Rollback to a specific update IDeas update --branch production --rollback-to-release-id=abc123def456
ℹ️
**Production Practice**: Always validate OTA updates on a staging branch before production rollout. If issues are detected, rolling back takes seconds using `--rollback-to-release-id`.
Scheduled Updates
For non-breaking updates, schedule them to deploy during off-peak hours:
eas update --branch production \ --message "Scheduled update: 2:00 AM PT" \ --scheduled
- name: Deploy OTA Update env: API_KEY: ${{ secrets.PRODUCTION_API_KEY }} ANALYTICS_TOKEN: ${{ secrets.ANALYTICS_TOKEN }} run: eas update --branch production --non-interactive
ℹ️
**Best Practice**: Never log secrets or pass them in command-line arguments. Use EAS CLI's built-in secret management or GitHub's encrypted environment variables exclusively.
Running QA with preview builds
Generate a Preview Build
eas build --platform ios --profile preview --non-interactive
Once complete, EAS generates a QR code. iOS testers can scan it with Expo Go to instantly test the app.
Pricing details change over time, so check Expo's official pricing page for the current numbers before committing to a plan.
ℹ️
**Pro Tip**: Batch preview builds on a separate branch to separate QA testing from production release builds. This optimizes build queue usage and costs.
Production release checklist
Before deploying Rork to production, verify:
Pre-Build Verification
[ ] eas.json production profile configured with correct settings
[ ] Apple Team ID and Google Play service account JSON registered
[ ] All required environment variables and secrets created in EAS
[ ] iOS certificates and provisioning profiles valid (not expired)
[ ] Android keystore properly configured and backed up
[ ] app.json version matches intended release version
Testing Phase
[ ] Preview build tested on iOS and Android devices
[ ] End-to-end tests pass (login, API calls, payments)
[ ] User reviews on App Store / Google Play reviewed
[ ] Support queue monitored for new issue reports
[ ] Rollback strategy prepared if critical bugs detected
Rollback Procedure
If critical issues emerge:
# View recent updateseas update --list --limit=5# Rollback to previous version immediatelyeas update --branch production --rollback-to-release-id=PREVIOUS_ID
What months of real-world use taught me
OTA updates earned their keep first. When one of my wallpaper apps shipped with a duplicated-row bug in its list pagination, the fix was JavaScript-only, so eas update delivered it the same day — no review queue, no one-to-two-day wait. Being able to fix a bug the day you find it quietly shows up in your review scores, too.
The free tier's build quota, on the other hand, does not survive six apps. Thirty builds a month sounds generous until production builds alone (six apps × two platforms) consume twelve, and preview builds eat the rest. My compromise: production builds go through EAS, day-to-day testing stays on local development builds and Expo Go, and I only pay for the months when releases pile up. If you ship weekly, the paid plan (from $99/month) pays for itself; for a once-a-month indie cadence, the free tier works with a little discipline.
Queue times deserve a mention as well. On the free tier, builds submitted during US daytime hours sometimes sat for 20–40 minutes before starting. Batching my builds into the JST morning — a quiet window for the build fleet — removed almost all of that friction.
Where to go next
Pick one existing Rork (Expo) project, run eas build:configure, and get a preview build onto your own device. The moment the cloud build finishes and installs from a QR code, you will feel how much of your release routine this can absorb. GitHub Actions integration can wait until the manual flow feels boring.
I hope this saves you a few release weekends. 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.