DEV Community

Isaac Addis
Isaac Addis

Posted on • Edited on • Originally published at isaacaddis.github.io

(EAS Custom Builds, Maestro Cloud) Expo + Maestro CI Pipeline Overviews

Pipeline overview

  • Push to main triggers a GitHub Action workflow
  • The workflow installs dependencies, installs EAS CLI, then runs an EAS build with a build-and-maestro-test profile
  • Artifacts and logs are uploaded for debugging.

Note: I led the creation of our mobile app CI pipeline.

EAS Custom Builds vs Maestro Cloud (cost-driven choice)

I implemented both EAS‑based and Maestro Cloud pipelines and validated they work

We run on EAS Build because it's significantly cheaper. As of Aug 24, 2025: EAS Starter Plan starts at $19/month; Maestro Cloud is about $212.50/month

EAS Custom Builds Configuration

Here is our build-and-maestro-test configuration (eas.json):

"build-and-maestro-test": { "withoutCredentials": true, "config": "build-and-maestro-test.yml", "android": { "buildType": "apk", "image": "latest" }, "ios": { "simulator": true, "image": "latest" }, "channel": "build-and-maestro-test" } 
Enter fullscreen mode Exit fullscreen mode

Here is the corresponding Github Actions workflow file:

name: EAS Build & Maestro Tests on: push: branches: - "main" pull_request: branches: - "main" jobs: build_and_test: runs-on: ubuntu-latest timeout-minutes: 120 steps: - name: Checkout repository uses: actions/checkout@v3 - name: Install Bun uses: oven-sh/setup-bun@v1 with: bun-version: latest - name: Install dependencies run: bun install - name: Install EAS CLI run: npm install -g eas-cli - name: Run EAS Build with Maestro Tests run: EXPO_TOKEN=${{ secrets.EXPO_TOKEN }} eas build --platform android --profile build-and-maestro-test --non-interactive 
Enter fullscreen mode Exit fullscreen mode

Maestro Cloud Configuration

Here is the Github Actions workflow file for this:

name: EAS Build & Maestro Tests on: push: branches: - "**" jobs: build_and_test: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v3 - name: Install Bun uses: oven-sh/setup-bun@v1 with: bun-version: latest - name: Install dependencies run: bun install - name: Install EAS CLI run: npm install -g eas-cli - name: Fetch Latest EAS Build Artifact run: | # Export Expo token for authentication export EXPO_TOKEN=${{ secrets.EXPO_TOKEN }} # Get latest build URL BUILDS_JSON=$(eas build:list --platform android --profile production --status finished --json --non-interactive) # Validate JSON response if [[ -z "$BUILDS_JSON" || "$BUILDS_JSON" == "[]" ]]; then echo "No completed builds found!" exit 1 fi # Extract the build URL BUILD_URL=$(echo "$BUILDS_JSON" | jq -r '.[0].artifacts.buildUrl') # Ensure a valid URL was extracted if [[ -z "$BUILD_URL" || "$BUILD_URL" == "null" ]]; then echo "No valid build URL found!" exit 1 fi echo "Downloading APK from $BUILD_URL" # Download the APK using Expo authentication curl -L -o app-release.apk $BUILD_URL echo "APK downloaded to app-release.apk" ls -la - name: Install Maestro CLI run: | curl -Ls "https://get.maestro.mobile.dev" | bash echo "$HOME/.maestro/bin" >> $GITHUB_PATH - name: Run Maestro Cloud Tests on APK uses: mobile-dev-inc/action-maestro-cloud@v1.9.6 with: api-key: ${{ secrets.MAESTRO_API_KEY }} project-id: ${{ secrets.PROJECT_ID }} app-file: app-release.apk workspace: maestro android-api-level: 33 env: | MAESTRO_TEST_EMAIL=${{ secrets.MAESTRO_TEST_EMAIL }} MAESTRO_TEST_PASSWORD=${{ secrets.MAESTRO_TEST_PASSWORD }} 
Enter fullscreen mode Exit fullscreen mode

Tips and tricks from our experience

These tests can be flaky:

  • Add short delays before interacting with components in dialogs
  • Use pixel coordinates when IDs aren't reliable
  • Use runScript for dynamic data
  • I tested locally on a Pixel 5 emulator (API 33)

Top comments (0)