How to set up a CI/CD workflow for Expo React Native application using Github Actions.


CI/CD is one of the most important practices of XP. Having set this up since the beginning can help in identify and fix issues earlier and faster time to market. Here at Saeloun, we make sure it gets set up since the start of the project.

Let us start setting up a CI/CD for Expo react-native application. First, we will set up the CI process so it gets run on each of the branches we create and then we will set up the CD process specific to the develop or main branch because we need to create builds for the latest changes that get merged to develop or main.

Continuous Integration

  • As we are using Github Actions, we need to create a ci.yml file inside the .github/workflows folder at the root of the project.
  • Add the name of the workflow and the action on which we need to trigger the workflow.
name: CI
on: push
  • As Workflows are composed of Jobs we need to add a Job with the name lint-and-test as we will be linting the code and running the test cases. Also, we need to specify the type of machine that will process a job in our workflow.
name: CI
on: push

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
  • As Job is composed of a series of steps, we need to add steps to cache and install the node modules, and finally run the lint and test cases. So, this is what our final ci.yml file will look like.
name: CI
on: [push]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      - name: Find yarn cache location
        id: yarn-cache
        run: echo "::set-output name=dir::$(yarn cache dir)"

      - name: JS package cache
        uses: actions/cache@v1
        with:
          path: $(( steps.yarn-cache.outputs.dir ))
          key: $(( runner.os ))-yarn-$(( hashFiles('**/yarn.lock') ))
          restore-keys: |
            $(( runner.os ))-yarn-

      - name: Install Node Modules
        run: yarn install

      - name: Run Lint
        run: yarn lint

      - name: Run tests
        run: yarn test  

Once we add this file and push the code, Github Actions will run the workflow and we can see the results on Github Actions Tab.

Continuos Deployment

To start with Continuos Deployment, we need to first create an EXPO_TOKEN from expo.dev and add it to the GitHub project’s settings so that Expo allows GitHub Actions to create a build.

Once this is done, create the eas.json file in the project root. This file specifies different profiles which can be used to create builds for different environments for example in our case we created a preview profile for development builds. It also specifies the type of packaging we need to use, credentialsSource to sign the build, and the distribution channel.

In our case, credentialsSource is set to remote which means Expo will automatically create the credentials to sign the app.

{
  "cli": {
    "version": ">= 0.52.0"
  },
  "build": {
    "preview": {
      "distribution": "internal",
      "android": {
        "buildType": "apk"
      },
      "credentialsSource": "remote"
    },
    "production": {}
  },
  "submit": {
    "production": {}
  }
}

Now we are ready to create a GitHub Actions workflow to create a build.

  • Create a cd.yml file inside the .github/workflows folder at the root of the project.
  • Add the name of the workflow and action along with the branch name on which we need to trigger the workflow.
name: build
on: 
 push:
  branches:
    - develop
  • Add the jobs build with ubuntu-latest as a runner machine.
  • Add a step to fetch EXPO_TOKEN from the project’s settings.
  • Add a step to set ENV.
  • Add a step to install the expo.
  • Add the steps to cache and install the node modules.
  • Finally, add a step to create a build.

Here is what our final build.yml looks like:-

name: build
on: 
 push:
  branches:
    - develop

jobs:
  build:
    name: EAS build
    runs-on: ubuntu-latest
    steps:
      - name: Check for EXPO_TOKEN
        run: |
          if [ -z "$(( secrets.EXPO_TOKEN ))" ]; then
            echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions"
            exit 1
          fi

      - name: "Set ENV"
        run: echo "$(BASE_URL)"     
        env:
          BASE_URL: https://exampleapp.com    

      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Setup Node
        uses: actions/setup-node@v2
        with:
          node-version: 16.x
          cache: yarn

      - name: Setup Expo
        uses: expo/expo-github-action@v7
        with:
          expo-version: latest
          eas-version: latest
          token: $(( secrets.EXPO_TOKEN ))

      - name: Find yarn cache
        id: yarn-cache-path
        run: echo "::set-output name=dir::$(yarn cache dir)"

      - name: Restore cache
        uses: actions/cache@v2
        with:
          path: "$(( steps.yarn-cache-path.outputs.dir ))"
          key: "$(( runner.os ))-yarn-$(( hashFiles('**/yarn.lock') ))"
          restore-keys: "$(( runner.os ))-yarn-"

      - name: Install dependencies
        run: yarn install --immutable

      - name: Publish build
        run: eas build --platform android --profile preview 

As it can be seen from the Publish build command we are creating an android build using the preview profile as mentioned above.

Now, once we push this file to develop branch, GitHub Actions will run this workflow and trigger the build to be created on the Expo platform. Once the build is created, we can always download it from Expo builds dashboard.

Join Our Newsletter