Manually running eas build and eas submit every time gets old fast. Let's automate it with GitHub Actions.
What We'll Set Up
- Run tests and lint on every push
- Build iOS and Android on pull requests
- Auto-submit to stores when you create a release
Prerequisites
- Expo project with EAS configured
- GitHub repository
- App Store and Play Store apps created
Step 1: Get Your Expo Token
Generate an access token:
eas login
eas credentialsOr get it from expo.dev/settings/access-tokens.
Add it to your GitHub repo: Settings → Secrets → New repository secret → Name it EXPO_TOKEN.
Step 2: Basic CI Workflow
Create .github/workflows/ci.yml:
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm testStep 3: Build Workflow
Create .github/workflows/build.yml:
name: EAS Build
on:
pull_request:
branches: [main]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Setup Expo
uses: expo/expo-github-action@v8
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Install dependencies
run: npm ci
- name: Build Android
run: eas build --platform android --profile preview --non-interactive
- name: Build iOS
run: eas build --platform ios --profile preview --non-interactiveStep 4: Production Build and Submit
Create .github/workflows/release.yml:
name: Release
on:
release:
types: [published]
jobs:
build-and-submit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Setup Expo
uses: expo/expo-github-action@v8
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Install dependencies
run: npm ci
- name: Build and Submit Android
run: |
eas build --platform android --profile production --non-interactive --auto-submit
- name: Build and Submit iOS
run: |
eas build --platform ios --profile production --non-interactive --auto-submitStep 5: Configure EAS for Auto-Submit
Update your eas.json:
{
"cli": {
"version": ">= 5.0.0"
},
"build": {
"preview": {
"distribution": "internal"
},
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {
"ios": {
"appleId": "your@email.com",
"ascAppId": "1234567890",
"appleTeamId": "ABCD1234"
},
"android": {
"serviceAccountKeyPath": "./google-service-account.json",
"track": "internal"
}
}
}
}Step 6: Add Store Credentials
For iOS:
Add these secrets to GitHub:
EXPO_APPLE_ID- Your Apple ID emailEXPO_APPLE_PASSWORD- App-specific password
For Android:
- Create a service account in Google Play Console
- Download the JSON key
- Base64 encode it:
base64 -i google-service-account.json - Add as
GOOGLE_SERVICE_ACCOUNT_KEYsecret
Update the workflow to create the file:
- name: Setup Google Service Account
run: echo "${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}" | base64 -d > google-service-account.jsonBonus: Version Bumping
Add automatic version bumping on release:
- name: Bump version
run: |
VERSION=${GITHUB_REF#refs/tags/v}
npx json -I -f app.json -e "this.expo.version='$VERSION'"My Workflow
Here's my typical flow:
- Push to feature branch → CI runs tests
- Open PR to main → Preview build created
- Merge to main → Nothing (just tests)
- Create GitHub release
v1.2.3→ Production build + auto submit
The whole process from tagging a release to seeing it in TestFlight/Internal Testing takes about 20-30 minutes, completely hands-off.
Troubleshooting
Build fails with credential errors:
Make sure EXPO_TOKEN is set correctly and has the right permissions.
iOS submit fails:
You need an app-specific password, not your regular Apple ID password. Generate one at appleid.apple.com.
Android submit fails:
The service account needs "Release manager" permissions in Google Play Console.
Cost Considerations
EAS Build has a free tier with limited builds per month. For more builds, you'll need a paid plan. GitHub Actions is free for public repos and has generous limits for private repos.
That's it! Now every release is just a git tag away from production.