EAS Build & Deploy
Complete guide for building and submitting your app using Expo Application Services (EAS). This page also explains how EAS fits into the current Ship React Native backend story: Convex is the recommended full backend, while Expo API Routes are the lighter server-side option.
Prerequisites
| Requirement | Details |
|---|---|
| Expo account | expo.dev/signup |
| EAS CLI | npm install -g eas-cli |
| Apple Developer account | Required for iOS — $99/year |
| Google Play account | Required for Android — $25 one-time |
Initial Setup
# Login to EAS
eas login
# Configure project (creates eas.json)
eas build:configureBuild Profiles
{
"cli": {
"version": ">= 12.0.0",
"appVersionSource": "remote"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"ios": { "simulator": true }
},
"preview": {
"distribution": "internal",
"android": { "buildType": "apk" }
},
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {
"ios": {
"appleId": "your@email.com",
"ascAppId": "1234567890",
"appleTeamId": "ABCDEF1234"
}
}
}
}| Profile | Purpose | Distribution |
|---|---|---|
development | Local dev with dev client | Internal (simulator) |
preview | QA / beta testing | Internal (APK / Ad-hoc) |
production | App Store / Play Store | Store |
Build Commands
# Preview build (internal testing)
eas build --platform ios --profile preview
eas build --platform android --profile preview
# Production build
eas build --platform ios --profile production
eas build --platform android --profile production
eas build --platform all --profile productionSubmit to App Stores
# Submit latest build
eas submit --platform ios
eas submit --platform android
# Submit specific build
eas submit --platform ios --id BUILD_IDEAS Environment Variables
EAS env vars set as
SECRET are ONLY available during EAS builds (native compile time). EAS Hosting deployed workers (API routes) can ONLY read PLAINTEXT env vars. This distinction caused hours of debugging across 5 production apps.| Variable | Visibility | Why |
|---|---|---|
OPENAI_API_KEY | PLAINTEXT | Must be readable by the deployed EAS Hosting worker at runtime |
ANTHROPIC_API_KEY | PLAINTEXT | Same — API routes need it at runtime, not build time |
EXPO_PUBLIC_REVENUECAT_IOS_KEY | PLAINTEXT in eas.json | EXPO_PUBLIC_* vars are baked into the JS bundle by Metro at build time — EAS Secrets are not available to Metro |
SENTRY_AUTH_TOKEN | SECRET | Only needed during the native build process for source map uploads |
Setting environment variables
# Set PLAINTEXT vars (for API routes / EAS Hosting)
eas env:create --name OPENAI_API_KEY --value sk-xxx --visibility plaintext --environment production
# Set SECRET vars (for build-time only)
eas env:create --name SENTRY_AUTH_TOKEN --value sntrys_xxx --visibility secret --environment production
# List all env vars
eas env:list
# EXPO_PUBLIC_ vars go in eas.json, not EAS secrets
# They must be inlined by Metro at bundle timeeas deploy --prod --environment production. The deployed worker caches its environment at deploy time.Backend Strategy
This boilerplate supports two server-side paths. Use Convex when you need auth, persistence, credits, and subscriptions. Use Expo API Routes when you mainly need secure AI proxy endpoints running on EAS Hosting.
Where EAS fits best
| Benefit | Detail |
|---|---|
| Great for app distribution | Build, submit, and update native apps with a single workflow |
| Great for API routes | Convenient hosting path when you choose Expo API Routes mode |
| Simple env management | Useful for build-time config and API route runtime envs |
| Works alongside Convex | EAS handles app delivery even when Convex is your main backend |
When to choose each backend mode
Choose Convex for serious product infrastructure. Choose Expo API Routes for lighter AI-only server needs.
API Routes Deployment
Expo API routes (src/app/api/*+api.ts) run server-side on EAS Hosting. They require a separate deploy step from the native app build.
Prerequisites
web.outputmust be"server"in app.json- API keys must be set as PLAINTEXT env vars in EAS (not SECRET)
- EAS project must be initialized (
eas init)
Deploy commands
# Step 1: Export the web build (generates server bundle with API routes)
npx expo export --platform web
# Step 2: Deploy to EAS Hosting
eas deploy --prod --environment production
# Verify deployment
curl https://your-app.expo.app/api/healthdev-server.js or set EXPO_PUBLIC_API_URL in your .env to point to the deployed production URL.Setting EXPO_PUBLIC_API_URL for development
# Point dev builds to the deployed EAS Hosting URL
EXPO_PUBLIC_API_URL=https://your-app.expo.appIn production EAS builds, EXPO_PUBLIC_API_URL can be empty — API routes use relative URLs automatically. But during development, you need to point to the deployed URL so your dev client can reach the APIs.
expo-constants Pin (Build Fix)
expo-constants above 55.0.4 have a podspec with escaped quotes that break Ruby parsing on EAS build servers. This causes Pod install failed errors.{
"dependencies": {
"expo-constants": "55.0.4"
}
}Pin to EXACT "55.0.4" — not ~55.0.4 or ^55.0.4. The old scripts/patch-expo-constants-podspec.js workaround is no longer needed with this pin.
.easignore (Faster Builds)
Add a .easignore file to exclude heavy folders from the EAS build upload. This significantly speeds up build times.
# Heavy folders not needed for the build
node_modules/
.git/
.expo/
ios/Pods/
ios/build/
android/build/
android/app/build/
android/.gradle/
# Working files
assets/source/
docs/
README.md
__tests__/
.husky/
.github/Troubleshooting
| Error | Fix |
|---|---|
| "No bundle identifier" | Set ios.bundleIdentifier in app.json |
| Signing errors | Run eas credentials to reset |
| "App ID not found" in ASC | Create the app in App Store Connect first, check bundle ID matches exactly |
| Android build fails | eas build --platform android --clear-cache |
| Pod install failed / podspec parse error | Pin expo-constants to exact "55.0.4" in package.json |
| API route returns 500 / "API key not configured" | API key must be PLAINTEXT in EAS env vars, not SECRET. Redeploy after changing. |
| API routes work in prod but not in dev | Set EXPO_PUBLIC_API_URL in .env to the deployed EAS Hosting URL |
EAS configured and ready to submit
eas.json, secrets workflow, and store submission guide all included.