Skip to content
Logo Theodo

Preview Branches for React Native with Expo

Mo Khazali6 min read

Banner with RN, Expo, and Github logos.

A Github Action to automatically generate preview branches using EAS (Expo Application Services) as part of a CI/CD workflow, creating live deployments that allow the reviewer to functionally check any changes in the app before the feature is merged into staging.

React Native developers often get the short end of the stick when it comes to DevEx tools. Due to the sheer number of web devs, the React ecosystem far exceeds that of its native counterpart. A couple of years ago when I first saw Netlify’s preview deployments, I was absolutely awestruck. I thought a CI step that automatically generated a link where you could preview the built code was the coolest thing since sliced bread. Over the years, this has become standard on pretty much all JAMStack hosting platforms, including Vercel, Cloudflare Pages, AWS Amplify,…

Using Preview Branches, you can avoid verifying that your app works after merging code into production, and bring forward the verification process into the code review stage. This comes with a whole host of benefits, namely:

  1. Shorter feedback cycles between code reviews and functionally checking changes.
  2. End-to-end visibility of changes as a reviewer.
  3. Fewer regressions being merged into actual SDLC environments (incl. staging and prod)

Recently, we’ve been using preview branches on our React Native projects and we’re excited to share our Github integration for React Native apps using Expo!

The tools is built on top of EAS and eas-cli which hosts the build and update processes on Expo’s cloud platform.

What is EAS?

EAS stands for Expo Application Services - it’s a suite of cloud services built by the folks at Expo. One of the major components of EAS is the build service. It basically allows you to build your app binaries, while abstracting away a lot of the complexity. EAS Build also handles over-the-air (OTA) updates for you. This means that so long as your native dependencies haven’t changed, you can push your app’s latest JS bundle to users and avoid needing to re-build.

Since we started using it, EAS has opened many doors to DevEx nirvana, including the prospect of Preview Branches! 🤩

CI Workflow Steps

The Github Action has 4 main steps:

  1. Install Expo & EAS ⚙️
  2. Generate Preview Deployment 🚀
  3. Post-merge Cleanup 🧹
  4. Deploy to main 📲

Workflow CI Diagram

1. Install Expo & EAS ⚙️

This step is pretty simple, and installs the dependencies needed to generate the preview branches (namely eas-cli).

Expo has docs on how this can be setup, which are linked here.

2. Generate Preview Deployment 🚀

At this stage, we create a new deployment environment (using an EAS branch) and update with the latest version of the code. This workflow is triggered when a PR is:

We use the eas update command and generate a new branch with the same name as the branch name of the pull request. The output from eas update’s JSON includes information like the Update ID and URI that can be used to preview the update in the Expo Go app.

We extract the necessary values from the JSON response, and generate a comment on the pull request that includes:

If the user pushes an update to the branch, we re-run the workflow, replacing the previous comment to avoid a stale update QR/URI being shown.

3. Post-merge Cleanup 🧹

It’s important to ensure that we’re not generating dead branches on every PR. We’ll want to teardown the branch we’ve generated with Expo after a PR gets merged onto the main branch or is closed. In order to do this, we have another workflow that runs on merge to main and deletes the channel and branch created by the EAS CLI when we called eas update.

  - name: Delete Channel
    run: eas channel:delete ${{ github.head_ref }} --non-interactive

  - name: Delete Branch
    run: eas branch:delete ${{ github.head_ref }} --non-interactive

⚠️ Note: it’s important to delete the channel before the branch as you can’t delete a branch that has a single channel associated with it. This has to do with how Expo define the relationship between channels and branches.

4. Deploy to main 📲

Once a PR gets merged, there will be new commits being added to the repo’s main branch. As a final step, we will run eas update on the main branch to make sure the app is updated fully.

The Result 🎉

We have fully automated ephemeral environments that are spun up when needed and torn down after the changes have been reviewed. 🙌

As shown below, a comment is added to every PR, where the reviewer is able to use their phone to scan the QR code and access the preview deployment of the app:

Comment from Github Action with Expo QR code and links to deployment preview

How to setup on your repo?

Prerequisites

⚠️ Note: we use the default install step from Expo, which uses yarn by default. If you use a different package manager (npm or pnpm), you will need to adjust the workflow inside .github/actions/install accordingly.

Setup Steps

We’ve created a repository with our workflow YAML files that you can clone and use in your own repos.

  1. Follow the Expo docs on setting up EAS CLI within your Github actions (mentioned in Step 1). This will require you to add a secret called EXPO_TOKEN which is mentioned in the Expo docs above.
  2. Copy the entirety of .github folder into your app and push the changes.

⚠️ Note: If you have your own workflow that deploys to the main branch, you can omit the .github/workflow/main-update.yml file.

And that’s pretty much it! 🙌

Next Steps

We have a barebones CI/CD pipeline for mobile apps - the next steps would be to extend the ephemerality to our backend and database deployments to get fully ephemeral environments.

Obviously, our yaml files are specific to Github Actions, but the steps should largely be common for any CI/CD tool, and can easily be ported over. As we expand to other CI/CD tools (such as GitLab CI), we will start porting over the same pipeline steps to utilise preview branching.

Feel free to reach out

If you have any opinions or suggestions to improve our CI/CD workflow, feel free to reach out to me on Twitter @mo__javad or open up an issue on Github. 🙂

Liked this article?