Skip to main content

Configuring CI/CD Pipelines

1. Setting Up GitHub Actions

Example: Basic GitHub Actions Workflow

name: Build and Deploy
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: npm install
      - name: Build Expo app
        run: npx expo build:web
Step Description Notes
name Build and Deploy Workflow name
on.push.branches [ main ] Triggers on push to main branch
jobs.build.runs-on ubuntu-latest Runner OS for the job
Note: Ensure that your GitHub repository has the necessary permissions and secrets configured for deployment.

2. Configuring EAS Build in CI

Example: EAS Build Configuration

{
  "build": {
    "production": {
      "distribution": "store",
      "android": {
        "buildType": "app-bundle"
      },
      "ios": {
        "buildType": "archive"
      }
    }
  }
}
Property Description Values
build.production Production build configuration object
build.production.distribution Where the build is distributed store, internal
build.production.android.buildType Android build type app-bundle, aab
build.production.ios.buildType iOS build type archive, ipa
Note: EAS Build supports both Android App Bundles and iOS Archives for distribution.
Warning: Ensure that your CI environment has the necessary credentials and permissions to access EAS services.

3. Running Tests in CI

Example: Setting up test command in CI

#!/bin/bash
# Run tests in CI environment
npm test
Command Description Notes
npm test Runs test suite defined in package.json Ensure tests are configured to run in headless mode
expo test Runs tests using Expo's test runner Supports Jest and other testing frameworks
Note: Configure your CI pipeline to run tests in a headless environment to avoid UI-related issues.
Warning: Make sure to set up proper test coverage reporting in your CI pipeline.

4. Building on Commit

Example: Building on Commit with GitHub Actions

name: Build and Deploy
on:
  push:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm install
      - name: Build app
        run: npx expo build:web
        env:
          EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
Step Description Command Notes
Checkout Check out the repository code actions/checkout@v3 Required for all CI workflows
Setup Node.js Install Node.js runtime actions/setup-node@v3 Ensure version matches local setup
Install dependencies Install project dependencies npm install Uses package-lock.json if present
Build app Build the Expo web application npx expo build:web Requires EXPO_TOKEN for publishing
Note: Ensure that the EXPO_TOKEN is stored as a secret in your repository settings for secure access.

5. Using GitHub Secrets

Example: Setting up GitHub Actions with Expo

name: Expo CI/CD
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm install
      - name: Build Expo app
        run: npx expo build:android
        env:
          EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
          EAS_BUILD_SECRET: ${{ secrets.EAS_BUILD_SECRET }}
Secret Name Description Usage
EXPO_TOKEN Expo CLI token for publishing builds Used by eas build or expo publish
EAS_BUILD_SECRET Secret for EAS Build configuration Required for secure EAS builds
Note: Store all sensitive credentials as GitHub Secrets in your repository settings.
Warning: Never commit secrets to your repository's source code.

6. Implementing Code Signing

Example: Expo Code Signing Configuration

{
  "expo": {
    "codeSigning": {
      "key": "path/to/code-signing-key.pem",
      "certificate": "path/to/code-signing-cert.pem"
    }
  }
}
Property Description Values
codeSigning.key Path to the private key file used for signing string
codeSigning.certificate Path to the certificate file used for signing string
Note: Code signing is required for production builds on iOS and Android to ensure app integrity.
Warning: Keep your code signing keys secure and never commit them to version control.

Workflow: Setting Up Code Signing for Expo

  1. Generate a code signing key and certificate using OpenSSL
  2. Store the key and certificate in a secure location (e.g., CI/CD secrets)
  3. Update app.json or app.config.js with the paths to these files
  4. Configure your CI/CD pipeline to use these files during build

7. Automating Store Submission

Example: EAS Build and Submit Configuration

{
  "build": {
    "production": {
      "distribution": "store",
      "android": {
        "buildType": "app-bundle"
      },
      "ios": {
        "buildType": "archive"
      }
    }
  },
  "submit": {
    "production": {
      "android": {
        "serviceAccount": "./path/to/service-account.json"
      },
      "ios": {
        "appleId": "user@example.com",
        "ascAppId": "123456789"
      }
    }
  }
}
Field Description Values Notes
build.production.distribution Target distribution channel store Submits to app stores
build.android.buildType Android build type app-bundle, aab App bundle is preferred for Google Play
build.ios.buildType iOS build type archive, ipa Archive is preferred for App Store
submit.android.serviceAccount Service account file path string Required for Google Play submission
submit.ios.appleId Apple ID for App Store Connect string Used to authenticate with Apple
submit.ios.ascAppId App Store Connect App ID string Unique identifier for the app in App Store Connect
Note: Ensure that the service account or Apple credentials are securely stored in CI/CD environment variables.
Warning: Store submissions require valid app signing keys and metadata. Misconfigurations can lead to failed submissions.

8. Deploying OTA Updates

Example: Configure OTA updates with EAS

eas update --branch production
Property Description Default
branch The branch to deploy the update to main
message Release message for the update None
platform Platform to deploy (ios, android, or all) all
Note: OTA updates are only available for managed workflow projects.
Warning: Ensure that your app's app.json or app.config.js is correctly configured for EAS updates before deploying.

OTA Update Process

  • Create a new build with EAS Build
  • Configure EAS Update to use the correct branch
  • Deploy the update using eas update
  • Users will receive the update automatically on next app launch

9. Using Fastlane Integration

Example: Fastlane Configuration for Expo

lane :release do
  ensure_git_status_clean
  git_pull
  cocoapods
  match(type: "appstore")
  build_ios_app(
    scheme: "Expo",
    export_method: "app-store"
  )
  upload_to_app_store
end
Fastlane Action Description Parameters
build_ios_app Builds the iOS app for distribution scheme: "Expo", export_method: "app-store"
upload_to_app_store Uploads the built app to App Store Connect
match Manages certificates and provisioning profiles type: "appstore"
Note: Ensure that your Fastlane configuration matches the Expo project's build settings and certificates.
Warning: Fastlane requires proper setup of Apple Developer credentials and certificates.

10. Implementing Beta Distribution

Example: Configure EAS Build for Beta

eas build --platform all --profile beta
Configuration Description Value
eas.json Build profile for beta distribution {"build": {"beta": {"distribution": "beta"}}}
build.profile Build configuration name "beta"
build.distribution Release type for distribution "beta"
Note: Ensure your app version is incremented for beta releases to avoid conflicts.
Warning: Beta builds must be signed with a valid distribution certificate.

Key Steps for Beta Distribution

  • Create a new build profile in eas.json
  • Set distribution to "beta"
  • Run eas build --profile beta
  • Upload to TestFlight or Google Play Console

11. Monitoring Build Status

Example: Expo Build Status Endpoint

const buildStatus = await fetch(
  'https://api.expo.dev/builds/123456789'
).then(res => res.json());
Field Description Values
status Current build status pending, running, success, failed
logs Build logs URL https://expo.dev/logs/123456789
buildId Unique identifier for the build 123456789
Note: Build status updates are available via the Expo CLI or API. Use expo build:status to check progress.
Warning: Build logs are only available for a limited time (typically 7 days) after the build completes.

12. Caching Dependencies

Example: Setting up dependency caching in GitHub Actions

name: Build and Cache Dependencies
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Cache node modules
        id: cache-modules
        uses: actions/cache@v3
        with:
          path: |
            **/node_modules
            /app/.cache
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
      - name: Install dependencies
        if: steps.cache-modules.outputs.cache-hit != 'true'
        run: npm ci
Cache Key Description Usage
node_modules Dependencies installed via npm or yarn Cache directory for package dependencies
.cache Expo and build cache directories Stores intermediate build artifacts
Note: Caching node_modules and .cache can significantly speed up CI builds by avoiding redundant installations.

Was this article helpful?