Implementing a CI/CD Deployment Pattern for React Native Expo Applications with Github Actions
Tags: reactnative, expo, githubactions, cicd
Published: 2023-12-10 15:22:30

Our deployment pattern leverages the Persistent Staging Flow directly from the [Expo documentation](https://docs.expo.dev/eas-update/deployment-patterns/#persistent-staging-flow). This flow is designed for continuous integration and delivery, with a focus on maintaining persistent "staging" and "production" branches.

## Key Aspects of the Deployment Pattern

**1. Creating Builds**
- Production Builds: Distinct builds tailored for the production environment.
- Testing Builds: Separate, dedicated builds for testing purposes.

**2. Testing Changes**
- Implement internal distribution builds for comprehensive pre-production testing.

**3. Publishing Updates**
- Utilize designated branches, like "staging" and "production", for streamlined update management.

## Application of the Pattern: A Practical Example

**Local Development**
- Begin with a feature branch (e.g., feature/dark-mode) based on the main branch.
- Develop the feature with an emphasis on coding, UI design, and local testing.

**Merging to Main**
- After development, commit the changes and push to feature/dark-mode.
- Merge into the main branch upon pull request approval.

**Testing in Staging**
- Merge updates from the main to staging.
- Trigger a staging build through GitHub Actions, followed by internal distribution for testing.

**Iterative Fixes and Updates**
- Address feedback, creating and merging fixed branches as necessary.
- Conduct additional testing after merging updates into staging.

**Final Deployment to Production**
- Confirm feature stability in staging before merging to production.
- Update version numbers in app.json/app.config.js and initiate automated production deployment via GitHub Actions.


## CI/CD Configuration Files
Setup the different profiles in build and submit sections in eas.json that are needed. Here is an example,

_**eas.json**_
```
{
 "build": {
   "development": {
     "developmentClient": true,
     "distribution": "internal"
   },
   "preview": {
     "channel": "staging",
     "distribution": "internal",
     "env": {
       "EXPO_PUBLIC_API_HOST": // your staging api url
     }
     // ...other values
     }
   },
   "production": {
     "channel": "production"
     "env": {
       "EXPO_PUBLIC_API_HOST": // your production api url
     }
     // ...other values
   }
 },
 "submit": {
   "production": {
       // This is optional if you already setup the service account key in your expo account
     "android": {
       "serviceAccountKeyPath": "../path/to/api-xxx-yyy-zzz.json",
       "track": "internal"
     },
     "ios": {
       "appleId": "john@turtle.com",
       "ascAppId": "1234567890",
       "appleTeamId": "AB12XYZ34S"
     }
   }
 }
}
```

**GitHub Actions YAML Configurations**
Set up your **EXPO_TOKEN** as a secret in your GitHub repository.

_**staging.yml**_
This job will create a staging build that you can distribute to your internal testers to test.
```
name: Build For Staging
on:
  push:
    branches: ["staging"]
jobs:
  build:
    name: Build For Staging
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 16.x
          cache: npm
      - name: Setup Expo and EAS
        uses: expo/expo-github-action@v8
        with:
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}
      - name: Install dependencies
        run: npm ci
      - name: Build For Staging
        run: eas build --profile preview --platform all --non-interactive
```

_**production.yml**_
This job will create a production build and submit this build to AppStore Connect and Google Play Console.
```
name: Build For Production
on:
  push:
    branches: ["production"]
jobs:
  build:
    name: Build For Production
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 16.x
          cache: npm
      - name: Setup Expo and EAS
        uses: expo/expo-github-action@v8
        with:
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}
      - name: Install dependencies
        run: npm ci
      - name: Build For Production
        run: eas build --profile production --platform all --non-interactive --auto-submit --clear-cache
```
---
There we have it!

Adopting the Persistent Staging Flow from the Expo documentation in our CI/CD deployment pattern offers a streamlined and effective approach for managing React Native Expo app development. By consistently utilizing "staging" and "production" branches, we ensure a smooth and continuous integration and deployment process, significantly enhancing our development efficiency and release quality.

Happy deploying 🚀