EAS Deployment Pipeline

Comprehensive guide to the Expo Application Services (EAS) mobile deployment pipeline for iOS and Android production builds and submission.

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 required
  • build - 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:

  1. 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
  2. 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
  3. Verify Organization Identity

    • Apple will contact you via phone/email
    • Verify business information
    • Accept Developer Agreement and Contracts
    • Gain access to Apple Developer portal
  4. 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:

  1. 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
  2. Create App Entry

    • Navigate to “Create app”
    • Enter app name: “Phenom”
    • Select category: “Photography” or “Utilities”
    • Duration: Minutes to complete
  3. 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
  4. 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
  5. 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:

ProfilePurposeDistributionUse Case
developmentDebug buildsInternalLocal testing, simulator
previewInternal testingInternalBeta testing, internal QA
productionApp Store readyStoreProduction 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:

  1. Select “iOS”
  2. Choose “Manage credentials”
  3. Verify that provisioning profiles and certificates are configured
  4. For production: Ensure “App Store” profile is created

For Android:

eas credentials

Steps:

  1. Select “Android”
  2. Choose “Create new Android Keystore”
  3. Select “App Signing by Google Play” (Google manages the keystore)
  4. 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:

SecretDescriptionExample
API_BASE_URLBackend API endpointhttps://api.phenom.app/v1
LOG_LEVELLogging verbosityinfo, debug, error
FEATURE_FLAGSFeature toggles{"newMapUI": true}
SENTRY_DSNError trackinghttps://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

  1. Log in to Google Play Console
  2. Select your app (Phenom)
  3. Navigate to TestingInternal Testing (or Production if ready)
  4. Click Create new release
  5. Click Browse files under “App bundles and APKs”
  6. Select the downloaded .aab (Android App Bundle) file
  7. Click Upload
  8. Add release notes (e.g., “Initial launch release”)
  9. Click Save

Step 5: Submit for Review

  1. Click Review at the bottom
  2. Verify all compliance information
  3. Click Submit for review
  4. 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:

  1. EAS authenticates with Apple
  2. Submits the .ipa to App Store Connect
  3. Initial processing: 5-15 minutes
  4. 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:

  1. Verify credentials in 1Password
  2. Check Apple account security (2FA, app-specific passwords)
  3. 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:

  1. Check app.json sdkVersion
  2. Ensure it matches installed Android SDK
  3. Update eas.json Android 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:

  1. Verify UDIDs are registered for ad-hoc distribution:
    cat eas.json | grep -A 10 "adhoc"
    
  2. Add device UDIDs to EAS credentials:
    eas credentials --platform ios --update-provisioning
    

Submission Errors

Error: App rejected: Missing privacy policy URL

Solution:

  1. Ensure privacy.url is set in app.json:
    "privacy": "https://phenom.app/privacy"
    
  2. Verify URL is accessible from the internet

Error: Google Play: Upload failed - Version code already exists

Solution:

  1. Increment version code in android/app/build.gradle:
    versionCode = 2  // Increment from 1
    
  2. 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 required
  • distribution - “internal” (testing) or “store” (production)
  • channel - Used with Expo Updates for managing releases
  • buildConfiguration - Debug or Release build type
  • resourceClass - Build server capacity (medium is standard)
  • env - Environment variables injected into build
  • appleTeamId - 10-character Apple Team ID
  • serviceAccountKeyPath - 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.json configured
    • 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:

  1. Configure Firebase project
  2. Generate Firebase service account key
  3. In eas.json, add Firebase configuration
  4. 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: version field (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

App Store Guidelines


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:

  1. Check Troubleshooting Section
  2. Review Expo Documentation
  3. Contact Expo support via dashboard

For App Store Rejections:

  1. Read rejection details carefully
  2. Consult App Store Review Guidelines
  3. 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