Boolean Build

Ship an Expo app to TestFlight without EAS

2026-10-14

EAS Build is the easy path — but sometimes you can’t use it: you don’t want the subscription, you’ve made custom native changes, or your CI owns the signing. You can do the whole thing locally with expo prebuild + xcodebuild. Here’s the pipeline, and the parts that bite.

1. Prebuild the native project

npx expo prebuild --platform ios --no-install

This generates ios/ from your config. (Keep ios/ out of the repo.)

2. Pods — with UTF-8, or CocoaPods crashes

cd ios
LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 pod install

Some Ruby versions choke on a non-UTF-8 locale here; setting LANG/LC_ALL avoids the cryptic crash.

3. Archive (Release)

xcodebuild archive \
  -workspace ios/YourApp.xcworkspace \
  -scheme YourApp \
  -configuration Release \
  -destination "generic/platform=iOS" \
  -archivePath build/YourApp.xcarchive \
  -allowProvisioningUpdates \
  DEVELOPMENT_TEAM=XXXXXXXXXX \
  CODE_SIGN_STYLE=Automatic

-allowProvisioningUpdates lets Xcode use the Apple ID already signed in, so you don’t need an API key or manually managed profiles.

4. Export + upload

xcodebuild -exportArchive \
  -archivePath build/YourApp.xcarchive \
  -exportOptionsPlist ios/ExportOptions.plist \
  -exportPath build/export \
  -allowProvisioningUpdates

ExportOptions.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>method</key><string>app-store-connect</string>
  <key>destination</key><string>upload</string>
  <key>teamID</key><string>XXXXXXXXXX</string>
  <key>uploadSymbols</key><false/>
</dict></plist>

Then the build shows up in App Store Connect → TestFlight.

The gotchas that cost the most time

None of this is exotic — it’s just a sequence the tooling doesn’t spell out. Script it once (release_ios.sh) and never think about it again.

A ready-made release_ios.sh (and the Android upload script) ships in the Expo Production Starter.