Skip to content

Expo Application Services (EAS) Setup

This document covers the complete setup and usage of Expo Application Services (EAS) for building and deploying the Coaching App to iOS and Android app stores.

Overview

EAS Build and EAS Submit are cloud services that make it easier to build and submit your app to app stores without needing to configure complex build environments locally.

Key Features:

  • Cloud-based builds (no need for macOS to build iOS apps)
  • Build profiles for development, preview, and production
  • Automatic code signing and provisioning
  • OTA (Over-The-Air) updates with EAS Update
  • Integration with App Store Connect and Google Play Console

Monorepo Configuration

This project uses Yarn workspaces. The following configuration ensures EAS Build works correctly:

.yarnrc.yml

nodeLinker: node-modules

This ensures packages are installed in proper node_modules directories that EAS Build can resolve.

.easignore

Located at frontend/.easignore, this controls what files EAS uploads:

# Include workspace root files
!../package.json
!../.yarnrc.yml
!../.yarn/**

# Include shared workspace package
!../shared/**

# Include parent node_modules for workspace hoisting
!../node_modules/**

# Exclude other workspaces
../backend/**
../docs/**

Metro Config

The metro config must extend @expo/metro-config (not expo/metro-config):

const { getDefaultConfig } = require('@expo/metro-config');

Prerequisites

Required Accounts

  1. Expo Account: Sign up at expo.dev
  2. Apple Developer Account: Required for iOS builds ($99/year)
  3. Google Play Developer Account: Required for Android builds ($25 one-time)

Local Setup

# Install dependencies
yarn install

# Login to Expo
yarn eas login

# Check EAS configuration
cd frontend && eas whoami

Configuration Files

eas.json

Located at frontend/eas.json, this file defines build profiles:

{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "ios": {
        "simulator": true,
        "bundleIdentifier": "pa.com.kaiju.coachingapp.dev"
      },
      "android": {
        "buildType": "apk",
        "package": "pa.com.kaiju.coachingapp.dev"
      }
    },
    "preview": {
      "distribution": "internal",
      "ios": {
        "simulator": false,
        "bundleIdentifier": "pa.com.kaiju.coachingapp"
      },
      "android": { "buildType": "apk" }
    },
    "production": {
      "distribution": "store",
      "ios": {
        "buildConfiguration": "Release",
        "bundleIdentifier": "pa.com.kaiju.coachingapp"
      },
      "android": { "buildType": "app-bundle" }
    }
  }
}

Bundle Identifiers:

  • Development: pa.com.kaiju.coachingapp.dev - For local development builds
  • Preview/Staging: pa.com.kaiju.coachingapp - For TestFlight/Internal Testing
  • Production: pa.com.kaiju.coachingapp - For App Store release

app.json

The EAS project ID is configured in frontend/app.json:

{
  "expo": {
    "extra": {
      "eas": {
        "projectId": "d6b1b4ba-b00a-4043-bbea-b5a23be9ef99"
      }
    }
  }
}

Build Profiles

Development

For local development and internal testing:

yarn eas:build:dev        # Both platforms
yarn eas:build:dev:ios    # iOS only
yarn eas:build:dev:android # Android only

Features:

  • Development client enabled
  • iOS simulator builds
  • Android APK (not AAB)
  • Debug configuration
  • Local API URL

Preview

For staging/QA testing before production:

yarn eas:build:preview        # Both platforms
yarn eas:build:preview:ios    # iOS only
yarn eas:build:preview:android # Android only

Features:

  • Internal distribution (TestFlight/Internal Testing)
  • Release configuration
  • Staging API URL
  • Device testing (not simulator)

Production

For app store release:

yarn eas:build:prod        # Both platforms
yarn eas:build:prod:ios    # iOS only
yarn eas:build:prod:android # Android only

Features:

  • Store distribution
  • Release configuration
  • Production API URL
  • Android App Bundle (AAB) for Play Store
  • iOS IPA for App Store

iOS Setup

1. Apple Developer Account Configuration

cd frontend
eas credentials

Select "iOS" and follow prompts to:

  • Set up Distribution Certificate
  • Set up Provisioning Profile
  • Configure Push Notification keys (if needed)

2. App Store Connect

  1. Create app in App Store Connect
  2. Update eas.json with your Apple details:
{
  "submit": {
    "production": {
      "ios": {
        "appleId": "your-email@example.com",
        "ascAppId": "1234567890",
        "appleTeamId": "ABCD123456"
      }
    }
  }
}

3. Build and Submit

# Build for production
yarn eas:build:prod:ios

# Submit to App Store
yarn eas:submit:prod

Android Setup

1. Generate Keystore

EAS can generate and manage your Android keystore automatically:

cd frontend
eas credentials

Select "Android" and follow prompts to generate a new keystore or upload existing one.

2. Google Play Console

  1. Create app in Google Play Console
  2. Create a service account for API access:
  3. Go to Setup → API access
  4. Create service account
  5. Download JSON key file
  6. Save as frontend/google-play-service-account.json
  7. Add to .gitignore

  8. Update eas.json with service account path:

{
  "submit": {
    "production": {
      "android": {
        "serviceAccountKeyPath": "./google-play-service-account.json",
        "track": "production"
      }
    }
  }
}

3. Build and Submit

# Build for production
yarn eas:build:prod:android

# Submit to Google Play
yarn eas:submit:prod

Environment Variables

Environment variables are configured per build profile in eas.json:

{
  "build": {
    "production": {
      "env": {
        "APP_ENV": "production",
        "API_URL": "https://coaching-app-backend.kaiju.com.pa"
      }
    }
  }
}

Sensitive Secrets

Store sensitive values as EAS Secrets:

# Set a secret
eas secret:create --scope project --name API_KEY --value "your-secret-key"

# List secrets
eas secret:list

# Delete a secret
eas secret:delete --name API_KEY

Reference secrets in eas.json:

{
  "build": {
    "production": {
      "env": {
        "API_KEY": "$API_KEY"
      }
    }
  }
}

Over-The-Air (OTA) Updates

EAS Update allows you to push JavaScript updates without app store review:

1. Configure Updates

Updates are configured in app.json:

{
  "expo": {
    "updates": {
      "url": "https://u.expo.dev/d6b1b4ba-b00a-4043-bbea-b5a23be9ef99"
    }
  }
}

2. Publish Update

yarn eas:update

# Or specify branch
cd frontend && eas update --branch production --message "Fix critical bug"

3. Update Channels

Map build profiles to update branches in eas.json:

{
  "build": {
    "production": {
      "channel": "production"
    },
    "preview": {
      "channel": "staging"
    }
  }
}

Common Workflows

First-Time Setup

# 1. Install dependencies
yarn install

# 2. Login to Expo
cd frontend
eas login

# 3. Configure credentials
eas credentials

# 4. Build development for iOS simulator
cd ..
yarn eas:build:dev:ios

Note: When prompted about custom metro config, select No to proceed. The config properly extends @expo/metro-config.

Release to Production

# 1. Update version in app.json
# 2. Test preview build
yarn eas:build:preview

# 3. Build production
yarn eas:build:prod

# 4. Submit to stores
yarn eas:submit:prod

Hotfix with OTA Update

# 1. Fix bug in code
# 2. Test locally
# 3. Push OTA update
yarn eas:update

Monitoring Builds

View Build Status

cd frontend
eas build:list

# View specific build
eas build:view [BUILD_ID]

Build Dashboard

View all builds at: https://expo.dev/accounts/kaiju-labs/projects/coaching-app/builds

Troubleshooting

Build Failures

  1. Check build logs: eas build:view [BUILD_ID]
  2. Validate configuration: cd frontend && eas config --type build
  3. Clear EAS cache: Include "cache": { "disabled": true } in build profile

Credentials Issues

# Reset iOS credentials
cd frontend
eas credentials -p ios

# Reset Android credentials
eas credentials -p android

Version Conflicts

Ensure all Expo packages are compatible:

cd frontend
npx expo install --check
npx expo install --fix

Best Practices

1. Version Management

  • Use semantic versioning (e.g., 1.0.0)
  • Increment version in app.json before each build
  • Use appVersionSource: "remote" to sync with store versions

2. API Environments

  • Development: http://localhost:8055
  • Preview/Staging: https://staging-api.coaching-app.com
  • Production: https://api.coaching-app.com

3. Testing

  • Test preview builds on real devices before production
  • Use internal distribution (TestFlight/Internal Testing) for QA
  • Verify deep linking and push notifications

4. Security

  • Never commit google-play-service-account.json
  • Use EAS Secrets for API keys and sensitive data
  • Rotate credentials periodically
  • Review app permissions in app.json

5. Build Optimization

  • Use app-bundle for Android production (required by Play Store)
  • Enable Hermes for better performance
  • Optimize images and assets
  • Remove console logs in production

Resources