EAS Deployment Pipeline
Categories:
EAS Deployment Pipeline
This guide provides comprehensive instructions for developers and release managers to deploy the Peregrine mobile application to iOS and Android stores using Expo Application Services (EAS).
Overview
The PhenomApp uses Expo Application Services (EAS) to automate mobile application builds and submissions to the Apple App Store and Google Play Console. EAS handles:
- Building iOS and Android applications from your codebase
- Managing signing certificates and provisioning profiles
- Submitting applications to app stores
- Managing multiple build profiles (development, preview, production)
- Distributing internal test builds
Key Resources:
Part I: Environment Setup
This section covers the initial setup required before you can use EAS to build and deploy the application.
Step 1: Install EAS CLI
The Expo Application Services Command Line Interface (EAS CLI) is the primary tool for managing builds and submissions.
npm install -g eas-cli
Verify the installation:
eas --version
Expected Output: Version number (e.g., 7.1.0 or higher)
Step 2: Authenticate with Expo
Log in to your Expo account. This account is shared across the team and is linked to the organization’s Expo project.
eas login
Credentials Location:
- Primary Storage: 1Password (search for “Expo Organization Credentials”)
- Alternative: AWS Secrets Manager (phenom-earth project)
What to Enter:
- Username: (See credential vault)
- Password: (See credential vault)
Verification:
eas whoami
Expected Output: Organization username and email address
Step 3: Verify Project Linking
Ensure the local repository is properly linked to the EAS project. The project link is stored in eas.json.
eas project:info
Expected Output:
Expo project: phenom-earth/peregrine
Project ID: [UUID]
Linked to: phenom-earth organization
If the project is not linked, initialize it:
# ONLY run this once per project (already configured)
eas project:init
Step 4: Review EAS Configuration (eas.json)
The eas.json file in the project root defines build profiles, submission settings, and platform-specific configurations. Review the file structure:
cat eas.json | head -50
Expected Structure:
cli.version- Minimum EAS CLI version requiredbuild- Build profiles (development, preview, production)submit- Submission profiles (iOS, Android)
See EAS Configuration Example for detailed structure.
Part II: Deployment Phases and Timeline
Mobile app deployment requires completing multiple sequential phases. Below is the realistic timeline for each phase.
Phase 1: Identity & Account Setup (2-4 Weeks Total)
This phase must be completed BEFORE any builds are created.
Apple Developer Program Enrollment (2-4 Weeks)
Timeline: 2-4 weeks Cost: $99/year Dependencies: Organization legal entity information
Steps:
Acquire D-U-N-S Number
- Navigate to Dun & Bradstreet
- Register your organization to obtain a D-U-N-S number
- Duration: 1-2 weeks
- This is a legal business identifier number required by Apple
Enroll in Apple Developer Program
- Go to Apple Developer Program
- Click “Start Your Enrollment”
- Select entity type (Individual, Company, Organization, Government)
- Enter D-U-N-S number
- Complete organization verification with Apple
- Pay $99 registration fee
- Duration: 2-4 weeks for Apple verification
Verify Organization Identity
- Apple will contact you via phone/email
- Verify business information
- Accept Developer Agreement and Contracts
- Gain access to Apple Developer portal
Obtain Team ID
- Log in to Apple Developer Account
- Navigate to “Membership” section
- Copy your Team ID (10-character alphanumeric)
- Store securely: Save in 1Password under “Apple Developer Team ID”
Verification Checklist:
- D-U-N-S number obtained
- Apple Developer Program enrollment complete
- Organization identity verified by Apple
- Team ID obtained and stored securely
Google Play Console Setup (2-3 Days)
Timeline: 2-3 days Cost: $25 one-time registration fee Dependencies: Payment method (credit card)
Steps:
Create Google Play Developer Account
- Go to Google Play Console
- Click “Create account”
- Enter developer name (use organization name)
- Accept developer agreement
- Pay $25 registration fee via credit card
- Duration: Minutes to complete
Create App Entry
- Navigate to “Create app”
- Enter app name: “Phenom”
- Select category: “Photography” or “Utilities”
- Duration: Minutes to complete
Setup Service Account & JSON Keys
- Go to Google Cloud Console
- Create service account with “Editor” role
- Generate JSON key file
- Store JSON key in secure location (AWS Secrets Manager or 1Password)
- Duration: 15 minutes
Configure Release Manager Permissions
- In Google Play Console, go to “Settings” → “Users and permissions”
- Add team members with “Release manager” role
- These users can submit builds to the Play Store
Enable App Signing
- In Google Play Console, go to “Setup” → “App signing”
- Enable “Google Play app signing”
- This allows Google to manage signing certificates
Verification Checklist:
- Google Play Developer account created
- App entry created in Play Console
- Service account JSON key generated and stored
- Team members have release manager permissions
- App signing enabled
Phase 2: Pipeline Configuration (Sprint 1-2)
Timeline: 1 Sprint (1-2 weeks) Dependencies: Phase 1 complete
Configure EAS Build Profiles
The eas.json file defines build configurations. Update or verify the following profiles:
Example Profile Structure:
{
"cli": {
"version": ">= 5.0.0"
},
"build": {
"development": {
"extends": "base",
"distribution": "internal",
"ios": {
"buildConfiguration": "Debug"
},
"android": {
"buildConfiguration": "debug"
}
},
"preview": {
"extends": "base",
"distribution": "internal",
"channel": "preview",
"ios": {
"buildConfiguration": "Release"
},
"android": {
"buildConfiguration": "release"
}
},
"production": {
"extends": "base",
"distribution": "store",
"channel": "production",
"ios": {
"buildConfiguration": "Release"
},
"android": {
"buildConfiguration": "release"
}
},
"base": {
"env": {
"NODE_ENV": "production"
}
}
},
"submit": {
"production": {
"ios": {
"appleTeamId": "XXXXXXXXXX",
"appleId": "user@example.com",
"appleIdPassword": "@keychain:ASC_PASSWORD"
},
"android": {
"serviceAccountKeyPath": "./credentials/google-play-key.json"
}
}
}
}
Profile Descriptions:
| Profile | Purpose | Distribution | Use Case |
|---|---|---|---|
development | Debug builds | Internal | Local testing, simulator |
preview | Internal testing | Internal | Beta testing, internal QA |
production | App Store ready | Store | Production release to App Store/Play Console |
Duration: 1-2 days
Configure Signing Credentials
EAS provides managed credential storage. Credentials are stored securely in Expo’s infrastructure.
For iOS:
eas credentials
Steps:
- Select “iOS”
- Choose “Manage credentials”
- Verify that provisioning profiles and certificates are configured
- For production: Ensure “App Store” profile is created
For Android:
eas credentials
Steps:
- Select “Android”
- Choose “Create new Android Keystore”
- Select “App Signing by Google Play” (Google manages the keystore)
- Save the keystore information securely
Duration: 1-2 hours
Configure Environment Variables
Set up environment-specific variables for API endpoints, logging, and feature flags.
eas secret:create
Common Secrets:
| Secret | Description | Example |
|---|---|---|
API_BASE_URL | Backend API endpoint | https://api.phenom.app/v1 |
LOG_LEVEL | Logging verbosity | info, debug, error |
FEATURE_FLAGS | Feature toggles | {"newMapUI": true} |
SENTRY_DSN | Error tracking | https://xxxxx@sentry.io/xxxxx |
Store secrets in:
- EAS Secrets (encrypted in Expo infrastructure)
- AWS Secrets Manager (for team reference)
- 1Password (for team sharing)
Duration: 1 day
Phase 3: Launch Process - First Submission
Timeline: 1-2 weeks Dependencies: Phase 1 + Phase 2 complete
Create First Production Build (Android)
Note: Google Play requires the first submission to be manually uploaded via the console.
Step 1: Prepare Release Branch
# Ensure all code is tested and ready
git checkout main
git pull origin main
git checkout -b release/v1.0.0
# Update version numbers if needed
# - app.json: "version": "1.0.0"
# - android/app/build.gradle: versionCode = 1
git commit -m "chore: Bump version to 1.0.0 for initial release"
git push origin release/v1.0.0
Step 2: Build Production APK/AAB
# Build Android App Bundle (recommended for Play Store)
eas build --platform android --profile production
Monitor the build:
- EAS CLI outputs a link to the build dashboard
- Dashboard shows real-time build progress
- Build typically takes 15-30 minutes
Expected Output:
Building for android
Platform: android
Profile: production
Build URL: https://expo.dev/builds/[BUILD_ID]
✓ Build complete
Download URL: https://[download-link].apk
Step 3: Download Build Artifact
# Download the APK/AAB file
# URL provided in EAS CLI output or available in dashboard
Step 4: Manually Upload to Google Play Console
- Log in to Google Play Console
- Select your app (Phenom)
- Navigate to Testing → Internal Testing (or Production if ready)
- Click Create new release
- Click Browse files under “App bundles and APKs”
- Select the downloaded
.aab(Android App Bundle) file - Click Upload
- Add release notes (e.g., “Initial launch release”)
- Click Save
Step 5: Submit for Review
- Click Review at the bottom
- Verify all compliance information
- Click Submit for review
- Google will review within 3-7 days
Duration for Manual Upload: 30 minutes
Create First Production Build (iOS)
Step 1: Build iOS App
eas build --platform ios --profile production
Step 2: Submit to TestFlight (Optional Pre-Release Testing)
Before submitting to the App Store, test with internal testers via TestFlight:
eas submit --platform ios --profile production --latest
This submits the build to TestFlight for internal testing.
Step 3: Submit to App Store
Once internal testing is complete:
eas submit --platform ios --profile production --latest \
--appStoreConnectVersion "1.0.0"
Expected Process:
- EAS authenticates with Apple
- Submits the
.ipato App Store Connect - Initial processing: 5-15 minutes
- Apple review: 24-48 hours typically
Duration: 45 minutes to 3 days
Store Review Timeline
Apple App Store:
- First Submission: 1-2 weeks (additional scrutiny for first release)
- Subsequent Updates: 24-48 hours
- Rejection Rate: ~20% on first submission (plan for resubmission)
Common Rejection Reasons:
- Missing privacy policy
- Unclear app functionality
- Insufficient metadata
- IDFA transparency issues
Google Play Console:
- Initial Review: 3-7 days
- Subsequent Updates: 2-3 hours to 1 day
- Rejection Rate: ~5% (more lenient than Apple)
Common Rejection Reasons:
- Misleading app description
- Lacks declared functionality
- Missing privacy policy
Part III: Build Commands Reference
This section provides quick reference for all common EAS commands.
Development Builds
Development builds include debugging tools and source maps.
# Build for iOS (development)
eas build --platform ios --profile development
# Build for Android (development)
eas build --platform android --profile development
# Build for both platforms
eas build --platform all --profile development
Use Case: Local testing, debugging, development
Duration: 20-30 minutes
Preview Builds (Internal Testing)
Preview builds are optimized for internal testing on staging environments.
# Build for iOS (preview)
eas build --platform ios --profile preview
# Build for Android (preview)
eas build --platform android --profile preview
# Build for both platforms
eas build --platform all --profile preview
Use Case: Internal QA testing, beta testing with limited external testers
Distribution: Ad-hoc for iOS, APK sharing for Android
Duration: 20-30 minutes
Production Builds
Production builds are optimized and ready for app store submission.
# Build for iOS (production)
eas build --platform ios --profile production
# Build for Android (production)
eas build --platform android --profile production
# Build for both platforms (parallel)
eas build --platform all --profile production
Use Case: Production release to App Store and Play Console
Duration: 30-45 minutes
Submission Commands
Submit to App Stores
iOS - Submit to App Store:
# Submit latest build
eas submit --platform ios --latest
# Submit specific build
eas submit --platform ios --id <BUILD_ID>
# Submit from URL
eas submit --platform ios --url https://[build-download-url]
Android - Submit to Google Play:
# Submit latest build to production
eas submit --platform android --track production --latest
# Submit to internal testing track
eas submit --platform android --track internal --latest
# Submit specific build
eas submit --platform android --id <BUILD_ID> --track production
Both Platforms:
# Submit latest builds to both platforms
eas submit --platform all --latest
Track Options (Android)
internal- Internal testing (100 testers)alpha- Closed alpha testing (1000s of testers)beta- Open beta testing (public but labeled beta)production- Production release to all users
Build Management Commands
View Build Status:
# List all recent builds
eas builds
# View details of specific build
eas builds --platform ios --limit 5
# Monitor build in progress
eas builds --platform all --status in-progress
Download Build Artifacts:
# Download from build dashboard URL (provided by EAS)
# Or use build details to get download link
eas builds --platform ios --json | jq '.[] | select(.id == "[BUILD_ID]") | .artifacts.buildUrl'
Part IV: Troubleshooting Common EAS Errors
Authentication Errors
Error: Not logged in
Solution:
eas login
# or
eas logout && eas login
Error: Unauthorized: Invalid Apple credentials
Solution:
- Verify credentials in 1Password
- Check Apple account security (2FA, app-specific passwords)
- Regenerate credentials:
eas credentials --platform ios --delete eas credentials --platform ios
Build Errors
Error: Cannot find module '@react-native-firebase/app'
Solution:
# Install dependencies
npm install
# Clear EAS build cache
eas build --platform ios --profile production --clear-cache
# Rebuild
eas build --platform ios --profile production
Error: Android SDK version mismatch
Solution:
- Check
app.jsonsdkVersion - Ensure it matches installed Android SDK
- Update
eas.jsonAndroid configuration:"android": { "sdk": "35.0.0" }
Certificate and Signing Errors
Error: Certificate has expired
Solution:
# Delete expired credential
eas credentials --platform ios --delete
# Recreate credential
eas credentials --platform ios
Error: Could not find a provisioning profile matching
Solution:
- Verify UDIDs are registered for ad-hoc distribution:
cat eas.json | grep -A 10 "adhoc" - Add device UDIDs to EAS credentials:
eas credentials --platform ios --update-provisioning
Submission Errors
Error: App rejected: Missing privacy policy URL
Solution:
- Ensure
privacy.urlis set inapp.json:"privacy": "https://phenom.app/privacy" - Verify URL is accessible from the internet
Error: Google Play: Upload failed - Version code already exists
Solution:
- Increment version code in
android/app/build.gradle:versionCode = 2 // Increment from 1 - Rebuild and resubmit:
eas build --platform android --profile production eas submit --platform android --latest
Part V: EAS Configuration Example (eas.json)
Here is a complete, production-ready eas.json configuration:
{
"cli": {
"version": ">= 5.0.0"
},
"build": {
"development": {
"extends": "base",
"distribution": "internal",
"channel": "development",
"ios": {
"buildConfiguration": "Debug",
"resourceClass": "medium"
},
"android": {
"buildConfiguration": "debug",
"resourceClass": "medium"
},
"env": {
"NODE_ENV": "development",
"API_ENV": "staging"
}
},
"preview": {
"extends": "base",
"distribution": "internal",
"channel": "preview",
"ios": {
"buildConfiguration": "Release",
"resourceClass": "medium"
},
"android": {
"buildConfiguration": "release",
"resourceClass": "medium"
},
"env": {
"NODE_ENV": "production",
"API_ENV": "staging"
}
},
"production": {
"extends": "base",
"distribution": "store",
"channel": "production",
"ios": {
"buildConfiguration": "Release",
"resourceClass": "medium"
},
"android": {
"buildConfiguration": "release",
"resourceClass": "medium"
},
"env": {
"NODE_ENV": "production",
"API_ENV": "production"
}
},
"base": {
"node": "20.11.0",
"npm": "10.5.2",
"inputs": {
"ios": true,
"android": true
},
"env": {
"EXPO_USE_LATEST_NATIVE_MODULES": "1"
}
}
},
"submit": {
"production": {
"ios": {
"appleTeamId": "XXXXXXXXXX",
"appleId": "releases@phenom.app",
"appleIdPassword": "@keychain:PHENOM_ASC_PASSWORD"
},
"android": {
"serviceAccountKeyPath": "./credentials/google-play-key.json",
"track": "production"
}
},
"preview": {
"android": {
"serviceAccountKeyPath": "./credentials/google-play-key.json",
"track": "internal"
}
}
}
}
Key Configuration Elements:
cli.version- Minimum EAS CLI version requireddistribution- “internal” (testing) or “store” (production)channel- Used with Expo Updates for managing releasesbuildConfiguration- Debug or Release build typeresourceClass- Build server capacity (medium is standard)env- Environment variables injected into buildappleTeamId- 10-character Apple Team IDserviceAccountKeyPath- Path to Google Play JSON key
Part VI: Complete Deployment Workflow
This section shows the complete end-to-end workflow from code commit to production release.
Prerequisites Checklist
Before following this workflow, ensure:
- Phase 1 (Identity Setup) complete
- Apple Developer Program enrolled
- Google Play Console account created
- Phase 2 (Pipeline Configuration) complete
- EAS CLI installed and authenticated
-
eas.jsonconfigured - Credentials set up
- Environment variables configured
- All tests passing locally and in CI/CD
Workflow Steps
1. Create Release Branch
# Start from main
git checkout main
git pull origin main
# Create release branch (use semantic versioning)
git checkout -b release/v1.0.0
# Update version in app.json
# Update CHANGELOG.md with release notes
# Commit
git commit -m "chore: Release v1.0.0"
# Push to origin
git push -u origin release/v1.0.0
2. Create Production Builds
# Ensure release branch is checked out
git checkout release/v1.0.0
# Build for both platforms
eas build --platform all --profile production
# Monitor builds at Expo dashboard
# Builds typically take 30-45 minutes
3. Test Builds Pre-Submission (Optional)
For iOS - Test with TestFlight First:
# Submit to TestFlight for internal testing
eas submit --platform ios --profile production --latest
# Have testers validate functionality
# Collect feedback for 2-3 days
4. Submit to App Stores
Submit iOS to App Store:
eas submit --platform ios --profile production --latest
Submit Android to Google Play:
# First submission: Android requires manual upload
# Use Google Play Console to upload the .aab file
# Subsequent submissions:
eas submit --platform android --profile production --latest
5. Monitor App Store Reviews
Apple App Store:
- Review typically takes 24-48 hours
- Check Apple Developer account for status updates
- Be prepared to address rejection reasons
Google Play Console:
- Review typically takes 2-3 hours to 1 day
- Often auto-approved if no policy violations
6. Merge Release Branch
Once both stores approve and app is live:
# Create pull request
gh pr create --title "Release: v1.0.0" \
--body "Deployed to App Store and Play Console"
# After approval, merge
git checkout main
git pull origin main
git merge release/v1.0.0
git push origin main
# Delete release branch
git branch -d release/v1.0.0
7. Create Release Tag
# Tag the release commit
git tag -a v1.0.0 -m "Version 1.0.0 - Production Release"
git push origin v1.0.0
# View all releases
git tag --list
Part VII: Advanced Topics
Using Channels with Expo Updates
Channels allow you to manage which builds are served to users without rebuilding the app.
Publish Update to Channel:
# Build with specific channel
eas build --platform all --profile production --channel production
# Later, publish update to that channel
expo publish --channel production
Automated CI/CD Integration
Integrate EAS builds into GitHub Actions for automatic deployment on tags.
Example .github/workflows/deploy.yml:
name: Deploy to App Stores
on:
push:
tags:
- 'v*'
jobs:
build-and-submit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install EAS CLI
run: npm install -g eas-cli
- name: Login to EAS
run: eas login --username ${{ secrets.EAS_USERNAME }} --password ${{ secrets.EAS_PASSWORD }}
- name: Build and Submit iOS
run: |
eas build --platform ios --profile production --wait
eas submit --platform ios --latest --auto-submit
- name: Build and Submit Android
run: |
eas build --platform android --profile production --wait
eas submit --platform android --latest --track production
Firebase App Distribution (Android)
Distribute internal builds to testers via Firebase App Distribution.
Steps:
- Configure Firebase project
- Generate Firebase service account key
- In
eas.json, add Firebase configuration - Testers install app from Firebase console link
See Firebase App Distribution Documentation for details.
Part VIII: Team Roles and Responsibilities
Release Manager
Responsibilities:
- Run EAS build commands
- Submit to app stores
- Monitor app store reviews
- Communicate release status to team
Required Access:
- EAS CLI authenticated
- Apple Developer Program Admin or App Manager role
- Google Play Console Release Manager role
Security & Credentials
Credential Storage:
- Apple ID credentials: 1Password secure note
- Google Play service account: AWS Secrets Manager
- EAS credentials: Managed by EAS (encrypted)
Who Has Access:
- Release managers only
- Stored in 1Password with team-only access
- Rotated annually
Version Management
Versioning Scheme: Semantic Versioning (MAJOR.MINOR.PATCH)
Version Locations:
app.json:versionfield (e.g., “1.0.0”)app.json:ios.buildNumber(e.g., “1”)android/app/build.gradle:versionCode(e.g., 1)
Update Process:
# Update all version fields before release
# Example: bumping from 1.0.0 to 1.0.1
# In app.json:
"version": "1.0.1",
"ios": {
"buildNumber": "2"
}
# In android/app/build.gradle:
versionCode = 2
# Commit
git commit -m "chore: Bump version to 1.0.1"
Useful Resources
Official Expo Documentation
- Expo EAS Build - Comprehensive Guide
- Expo EAS Submit - App Store Integration
- EAS Credentials Management
- EAS Build Configuration (eas.json)
App Store Guidelines
Related Documentation
- TestFlight Guide - iOS internal testing
- Feature Branch Builds - Building from feature branches
- Device UDIDs - Managing test device identifiers
- Project Architecture - Technical architecture overview
FAQ
Q: How long does an EAS build take? A: Typically 20-45 minutes depending on platform, build complexity, and queue. Development builds are faster than production builds.
Q: Can I build for both platforms simultaneously?
A: Yes, use --platform all to queue builds for both iOS and Android in parallel.
Q: What if my build is rejected by the app store? A: Read the rejection reason carefully, address the issue, increment version code/build number, rebuild, and resubmit.
Q: How do I test a production build before submitting to stores? A: Use the “preview” profile to build and distribute internally via TestFlight (iOS) or Firebase App Distribution (Android).
Q: Can I revert a build? A: Yes, you can unpublish from TestFlight/Play Console and resubmit a previous build. However, app stores may have stricter review on resubmission.
Q: How do I handle secrets (API keys, etc.) in EAS builds?
A: Use eas secret:create to securely store secrets in EAS infrastructure. Secrets are injected at build time and never exposed in the binary.
Support and Escalation
For Technical Issues:
- Check Troubleshooting Section
- Review Expo Documentation
- Contact Expo support via dashboard
For App Store Rejections:
- Read rejection details carefully
- Consult App Store Review Guidelines
- Make changes and resubmit
For Team Questions:
- Check #deployment Slack channel
- Review team wiki for deployment history
- Schedule sync with release manager
Last Updated: January 21, 2026
Document Version: 1.0.0
Document Owner: Peregrine Development Team
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.