DEV Community

Cover image for Don't Pay for EAS! How to Set Up an EAS Local Build on GitHub Actions
Rodrigo Gomez Palacio
Rodrigo Gomez Palacio

Posted on • Edited on

Don't Pay for EAS! How to Set Up an EAS Local Build on GitHub Actions

You're out of credits!

Should you pay for EAS?

If you're a React Native developer using Expo, you might be familiar with the convenience of Expo Application Services (EAS). EAS provides a suite of tools that streamline the process of developing and deploying your React Native apps.

One drawback of EAS is the price, which at $1-$4 per build may quickly add up for a developer just getting started on a project.

Luckily, one of the great features of the EAS CLI is the ability to perform local builds, and integrating this with GitHub Actions can significantly automate your development workflow and save you money!

In this post, we'll walk through the steps to set up an EAS local build on GitHub Actions.

EAS CLI + Github

Pricing & Build Times

It's important to compare prices and build times, to see when this implementation makes sense.

Let's start with GitHub Actions. If you're trying to optimize for cost, you're likely on the free GitHub plan or the basic $4 Github Teams/Pro plan. You're going to need to run iOS builds on a macOS while Ubuntu should work just fine for Android.

While build times vary, for simplicity, an average build takes about 35 minutes. At $0.008 PPM (price per minute) for Ubuntu 2-core and $0.08 PPM for macOS 3-core, that comes out to $0.28 per build for Android and $2.80 for iOS. That's an expensive iOS build.

Now let's look at EAS pricing. Depending on your choice of resources, your potential EAS build will use more cores and thus run a lot faster than on GitHub Actions. That may be worth paying for depending on your needs.

EAS Pricing

As you can see above, however, builds are pricy on EAS as well. That said, if build time is not a priority, you can find big savings on the Android side by going with GitHub Actions given the low cost of running Ubuntu.

Thus, your choice between EAS or GitHub Actions depends largely on a) how fast you need the build to run, and b) the frequency of your builds since running lots of builds will quickly add up.

For iOS builds, I think EAS comes out slightly ahead at a flat $2 per build if you go with the iOS medium worker size.

Setup

Step 1: Understanding the Prerequisites

Before diving into the setup, ensure you have:

  • A React Native project managed by Expo.
  • A GitHub repository for your project.
  • Basic knowledge of GitHub Actions and workflows.

Step 2: Setting Up Your GitHub Actions Workflow

Create a Workflow File:
In your project repository, create a new file in the .github/workflows directory. You can name it something like build.yml.



name: Build App
on:
  workflow_dispatch:
    inputs:
      os:
        type: choice
        description: OS to build on. Ubuntu is faster, MacOS supports iOS builds
        options:
          - macos-latest
          - ubuntu-latest
      platform:
        type: choice
        description: Platform to build for
        options:
          - android
          - ios
      profile:
        type: choice
        description: Build profile to use
        options:
          - development
          - preview
          - production
      should_submit:
        type: boolean
        description: Whether to perform the submit step
        required: true
        default: false
jobs:
  build:
    runs-on: ${{ github.event.inputs.os }}
    strategy:
      matrix:
        node: [18.x]
    steps:
    - name: 🏗 Setup repo
      uses: actions/checkout@v2

    - name: 🏗 Setup Node
      uses: actions/setup-node@v2
      with:
        node-version: ${{ matrix.node }}
        cache: yarn

    - name: 🏗 Setup Expo and EAS
      uses: expo/expo-github-action@v7
      with:
        token: ${{ secrets.EXPO_TOKEN }}
        expo-version: latest
        eas-version: latest

    - name: 📦 Install dependencies
      run: yarn

    - name: 📋 Test project
      run: yarn test

    - name: 👷 Build app
      run: |
        eas build --local \
          --non-interactive \
          --output=./app-build \
          --platform=${{ github.event.inputs.platform }} \
          --profile=${{ github.event.inputs.profile }}

    - name: 🚢 Submit
      if: ${{ github.event.inputs.should_submit }}
      run: eas submit -p ${{ github.event.inputs.platform }} --profile ${{ github.event.inputs.profile }} --path app-build



Enter fullscreen mode Exit fullscreen mode

Add Required Secrets:
For EAS to work, you need to add your Expo credentials as secrets in your GitHub repository. Go to your repository Settings -> Secrets and variables -> Actions. This is where you will paste in your access token. Double-check that you are creating the robot token at the right level (e.g. wherever your app is).

Github Secrets

Finally, add any other required secrets you may need. A common example is the Google Services files.

Google Services Files
If you are not using Google Services files, skip ahead.

Problem: consider the scenario where your project needs these files, but you don't want to commit them. If that's the case, Github Actions wouldn't have access to their contents.

Solution: base64-encode the files, add them as secrets to Github, and then use a pre-install hook to re-create the files in Github Actions' cloud environment.

  1. $ base64 -i googleServices/google-services.json (repeat for Plist, other files)
  2. Add encoded strings as secrets to Github Actions
  3. Write a script to decode them into their original files: ```sh

!/bin/bash

Create the directory if it doesn't exist

mkdir -p ./googleServices

Decode the base64 strings and create the files

echo $GOOGLE_SERVICES_JSON_BASE64 | base64 --decode > ./googleServices/google-services.json
echo $GOOGLE_SERVICES_PLIST_BASE64 | base64 --decode > ./googleServices/GoogleService-Info.plist

4. Call that script from the `eas-build-pre-install` hook in your package.json.
5. Make the variables accessible via our build YML:

```yml


- name: 👷 Build app
      env:
        GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}
        GOOGLE_SERVICES_PLIST_BASE64: ${{ secrets.GOOGLE_SERVICES_PLIST_BASE64 }}
        GOOGLE_SERVICES_JSON: ${{ vars.GOOGLE_SERVICES_JSON }}
        GOOGLE_SERVICES_PLIST: ${{ vars.GOOGLE_SERVICES_PLIST }}


Enter fullscreen mode Exit fullscreen mode

Note that in this example, I am using GOOGLE_SERVICES_JSON and GOOGLE_SERVICES_PLIST as well. These contain the paths to the files.

Github Variables

This is applicable if you don't have a hard-coded path in your app.json / app.config.js:



ios: {
googleServicesFile: process.env.GOOGLE_SERVICES_PLIST,
}

Enter fullscreen mode Exit fullscreen mode




Step 3: Testing the Workflow

Once you've set up the workflow file:

  1. Commit and Push: Commit the changes and push them to your repository.
  2. Trigger the build via the Github Actions tab.
  3. Click on the build to monitor it.

Step 4: Debugging and Optimization

  • If the build fails, check the logs in the Actions tab for errors.
  • Optimize your workflow by caching dependencies or splitting jobs.
  • If you know your tests pass, exclude that step and others to iterate more quickly until your build is stable.

Conclusion

Integrating EAS local builds into GitHub Actions can greatly enhance your CI/CD pipeline and save you some of the green. Remember, this setup might vary slightly depending on your project's specific needs, so feel free to adjust it as necessary.

And finally please feed the algorithm and give me some feedback if my post helped you 🙏!

Follow Me


LinkedIn Badge


Twitter Badge

Check out my other articles and projects!

Top comments (9)

Collapse
 
arafat_alim profile image
ARAFAT AMAN ALIM

Could you please provide your Git Repo for this demo? I just wanted to see your android directory, eas.json file ?

Collapse
 
imtiajbinaoual profile image
Imtiaj Aoual

Hi, getting an error on the android build.
Android Gradle plugin requires Java 17 to run. You are currently using Java 11.
Any suggestions on how to fix this?

Collapse
 
soyoka profile image
Soyoka

just add

this line after the yarn install

- name: Setup Java 17
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'

Collapse
 
omardiaa48 profile image
Omar Elwakeel

I keep getting base64: invalid input what could be the problem?

Collapse
 
omardiaa48 profile image
Omar Elwakeel

Never mind, I figured it out, for multi line base64 input it's prefered to use the following echo $GOOGLE_SERVICES_JSON_BASE64 | base64 -di >./google-services.json, not di instead of --decode or d

Collapse
 
martydevs profile image
Andre Marti

Thanks for this awesome article, i'm learning the expo platform so this resource is kinda gold mine.

Greetings from México 🤟

Collapse
 
rgomezp profile image
Rodrigo Gomez Palacio

My pleasure Andre. Greetings also from Mexico!

Collapse
 
naguibihab profile image
Naguib Ihab

Great article Rodrigo, do you have any articles about running local builds as well?

Collapse
 
rgomezp profile image
Rodrigo Gomez Palacio

Thanks Naguib. I don't.

Are you referring to running Expo builds locally or the GitHub Action locally?