DEV Community

Cover image for Automate React Native App Updates with Fastlane & Remote Config
PEAKIQ
PEAKIQ

Posted on • Originally published at peakiq.in

Automate React Native App Updates with Fastlane & Remote Config

Originally published on PEAKIQ

Source: https://www.peakiq.in/blog/automating-app-updates-in-react-native-with-fastlane-and-remote-config


Automating App Updates in React Native with Fastlane and Remote Config

Managing app updates across iOS and Android is repetitive work. Fastlane automates the build and release pipeline, while Firebase Remote Config lets you enforce a minimum required version without shipping a new build to change the threshold. Together they give you a reliable, low-maintenance update system.

This guide walks through setting up both, then connecting them via a GitHub Actions workflow.


Prerequisites

  • A React Native project
  • A Firebase project with Remote Config enabled
  • Fastlane installed locally
  • Basic familiarity with GitHub Actions

Step 1 — Set Up Fastlane

Initialize Fastlane in your project root:

fastlane init
Enter fullscreen mode Exit fullscreen mode

Follow the prompts to configure it for your project. This creates a fastlane/ directory containing a Fastfile and an Appfile.

Update your Fastfile with lanes for both iOS and Android. Each lane should handle the steps relevant to your release process — incrementing the build number, running tests, building the app, and uploading to the App Store or Google Play.

A minimal Android lane looks like this:

lane :android_deploy do
  gradle(task: 'bundle', build_type: 'Release')
  upload_to_play_store(track: 'internal')
end
Enter fullscreen mode Exit fullscreen mode

And for iOS:

lane :ios_deploy do
  match(type: 'appstore')
  build_app(scheme: 'YourApp')
  upload_to_app_store
end
Enter fullscreen mode Exit fullscreen mode

Customize these based on your signing setup, test requirements, and target release track.


Step 2 — Use Remote Config for Update Checks

Configure the parameter in Firebase

In the Firebase Console, go to Remote Config and create a new parameter named minimum_required_version. Set its default value to the minimum version string you want to enforce, for example 2.0.0.

When you want to raise the minimum — after deprecating an old API, fixing a critical bug, or shipping a breaking change — update this value in the console and publish. No new app build required.

Fetch and check the version in your app

Install the required packages if you have not already:

npm install @react-native-firebase/app @react-native-firebase/remote-config react-native-device-info
cd ios && pod install
Enter fullscreen mode Exit fullscreen mode

Then add the version check to your app entry point:

import { useEffect } from 'react';
import { Alert, Linking } from 'react-native';
import DeviceInfo from 'react-native-device-info';
import remoteConfig from '@react-native-firebase/remote-config';

const useUpdateCheck = () => {
  useEffect(() => {
    async function checkForUpdate() {
      await remoteConfig().fetchAndActivate();

      const minimumRequiredVersion = remoteConfig()
        .getValue('minimum_required_version')
        .asString();

      const currentVersion = DeviceInfo.getVersion();

      if (compareVersions(currentVersion, minimumRequiredVersion) < 0) {
        Alert.alert(
          'Update Required',
          'A new version of the app is available. Please update to continue.',
          [
            {
              text: 'Update Now',
              onPress: () => {
                // Android
                Linking.openURL('market://details?id=com.yourapp.package');
                // iOS — replace with your App Store URL
                // Linking.openURL('itms-apps://itunes.apple.com/app/idYOURAPPID');
              },
            },
          ],
          { cancelable: false }
        );
      }
    }

    checkForUpdate();
  }, []);
};

export default useUpdateCheck;
Enter fullscreen mode Exit fullscreen mode

Call useUpdateCheck() from your root component. The { cancelable: false } option on the alert prevents users from dismissing the prompt without updating.

You will need a compareVersions utility that parses semver strings and returns a negative number if the first argument is older than the second. A simple implementation:

const compareVersions = (a, b) => {
  const pa = a.split('.').map(Number);
  const pb = b.split('.').map(Number);
  for (let i = 0; i < 3; i++) {
    if ((pa[i] || 0) < (pb[i] || 0)) return -1;
    if ((pa[i] || 0) > (pb[i] || 0)) return 1;
  }
  return 0;
};
Enter fullscreen mode Exit fullscreen mode

Step 3 — GitHub Actions Workflow

Create the workflow file

Add a workflow at .github/workflows/deploy.yml:

name: Deploy React Native App

on:
  push:
    branches:
      - main

jobs:
  deploy-android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm install
      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.1'
          bundler-cache: true
      - name: Deploy Android
        run: bundle exec fastlane android_deploy
        env:
          FASTLANE_JSON_KEY_DATA: ${{ secrets.FASTLANE_JSON_KEY_DATA }}

  deploy-ios:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm install && cd ios && pod install
      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.1'
          bundler-cache: true
      - name: Deploy iOS
        run: bundle exec fastlane ios_deploy
        env:
          FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
          APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
Enter fullscreen mode Exit fullscreen mode

Add GitHub Secrets

In your repository, go to Settings > Secrets and variables > Actions and add the secrets referenced in the workflow:

Secret What it holds
FASTLANE_JSON_KEY_DATA Google Play service account JSON key
FASTLANE_USER Apple ID used for App Store Connect
MATCH_PASSWORD Password for your Fastlane Match certificate repo
APP_STORE_CONNECT_API_KEY App Store Connect API key JSON

Push changes to the main branch to trigger the workflow.


How It All Connects

Once this is in place, the release flow works like this:

  1. Push to main — GitHub Actions builds and deploys the app via Fastlane
  2. The new build ships to users through the App Store or Google Play
  3. When you need to force an update, raise minimum_required_version in Firebase Remote Config and publish
  4. On next app launch, users running an older version see the mandatory update prompt

No code change or new release is needed to adjust the minimum version threshold — that control lives entirely in Firebase.


Notes

  • Always test the compareVersions logic with edge cases — versions like 1.10.0 vs 1.9.0 trip up naive string comparison.
  • Consider adding a fetchAndActivate timeout via remoteConfig().setConfigSettings({ fetchTimeMillis: 3000 }) to avoid blocking app startup if Firebase is slow to respond.
  • For iOS, make sure the Linking.openURL target uses the correct itms-apps:// scheme with your actual App Store app ID.

Top comments (0)