(CI/CD) Multi-Environment deployment for a React App on Firebase, using GitHub Actions
By: Gio Logist
Tags: JavaScript, React, Firebase, Continuous Integration, Github Actions

Deploying to Firebase has never been easier. Here, we’ll cover how to automate your workflow, in order to test & deploy to multiple environments. This will assist in rapid iterations to your app, without constantly pushing breaking changes to production. The goal is to have an environment for your users (production), an environment to approve changes prior to shipping (staging) and an environment that’s actively being worked on (development).

By the end of this article, your app will automatically be tested & deployed to a specific Firebase Project (one per environment) simply by pushing to GitHub. Although we go extremely in-depth in this article, the end result is rather simple. The commits can be seen here and are kept to one commit per step.

For the sake of this article, we’ll assume you’re unfamiliar with a few terms.

Multi-Environment Deployment : The standard practice for developing & testing changes in an isolated environment.

: The standard practice for developing & testing changes in an isolated environment. CI/CD : Continuous Integration is the practice of merging all outstanding changes in a codebase, as often as possible. Being sure to test at all points. Continuous deployment is the practice of automating deployments to your users. Getting them new updates regularly.

: Continuous Integration is the practice of merging all outstanding changes in a codebase, as often as possible. Being sure to test at all points. Continuous deployment is the practice of automating deployments to your users. Getting them new updates regularly. Firebase : A mobile and web application development platform, owned by Google, that provides a number of products for any real world app. In this article, we’ll only be using “Firebase Hosting”.

: A mobile and web application development platform, owned by Google, that provides a number of products for any real world app. In this article, we’ll only be using “Firebase Hosting”. Github Actions : Allows you to create different workflows in order to automate certain tasks, such as CI/CD.

: Allows you to create different workflows in order to automate certain tasks, such as CI/CD. GitFlow: A widely adapted structure for naming your git branches.

There are a few articles on deploying a React App to Firebase, using GitHub Actions. This article aims to build upon that, adding multi-environment deployment. In addition, we opted not to use any pre-existing GitHub Actions for Firebase, in order to reduce the level of abstraction and allow you to see exactly what’s happening.

Prerequisites

Firebase Projects set up. You will need one project per environment. (IE: App Dev, App Staging, App Production)

Firebase CLI installed

GitHub repo, for running actions.

Step 1) Initialize your react app

view commit

Nothing special here, feel free to skip this, if you’ve already got your react app set up.

npx create-react-app myapp

Step 2) Initialize Firebase Hosting

view commit

cd myapp

firebase init # Which Firebase CLI features do you want to set up for this folder?

# Firebase Hosting # Select a default Firebase project for this directory

# (recommend you use your "dev" project for now, but any is fine) # What do you want to use as your public directory?

# build # Configure as a single-page app (rewrite all urls to /index.html)?

# y # File public/index.html already exists. Overwrite?

# n

Now, merge the .gitignore file Firebase uses with the one React automatically created. You can find the file here. Just copy and append it to the one you have locally. This is needed, at the time of writing, since Firebase doesn't automatically overwrite your current .gitignore.

Step 3) Initialize CI&CD w/Github Action

view commit

First, you’ll need to generate a Firebase CI token. This is needed in order for GitHub to authenticate to Firebase. Allowing you to deploy.

firebase login:ci

Caution: this token can be used to perform almost any task on any Firebase project you have access to. Save it. If, for any reason, your token becomes compromised, you can run the following command: firebase logout --token YOUR_TOKEN

Now, you’ll need to add your Firebase token to your repo’s secrets. Navigate to your GitHub repo, go to “Settings -> Secrets -> Add a New Secret”.

Name: CI_FIREBASE_TOKEN

Github Secrets

Note: Alternatively, you can name this FIREBASE_TOKEN, if you want to avoid passing the token explicitly during the deployment. more here.

Now that we’re all set up, let’s create our initial workflow. Create a file at .github/workflows/firebase_web.yml , with the contents below.

Github Workflow to deploy a single firebase project

Workflow explained

Curious as to what’s happening? We’re creating a workflow that’s triggered whenever a push is made. The workflow runs on Ubuntu. We checkout the current branch, this way the code we’re working on is the one that’s executed. Then, we install Node, which is needed by Firebase. After that, we run yarn (npm can also be used just fine) to install dependencies. Before deploying, it’s always best to test. We do that with the same test script React ships with. Only this time, we make sure to specify `CI=true`, which tells the React script that we’re working in a [CI environment](https://create-react-app.dev/docs/running-tests/#continuous-integration). From there, we run the typical “build” command that React ships with. After the build is complete, we deploy using Firebase CLI. We explicitly pass in our token (for authentication) & a message. The message consists of the GitHub commit message and a link to the workflow ran. This message will show in the Firebase console and will be useful, in knowing which commit triggered the current deployment.

Now, add firebase-tools as a dev dependency in your package.json

"devDependencies": {

"firebase-tools": "^7.7.0"

},

You should be able to push to GitHub and see a successful action now : )

git add .

git commit -m 'Step 3) Initialize CI&CD w/Github Action'

git push

Success 🚀

Github Workflow

And if we head on over to Firebase Console -> Hosting, we’ll see our latest deployment along with the message we configured ⚡️

Firebase Hosting — Release History

Brief Recap

In Steps 1–3, we developed a workflow which is capable of automating our testing & deployment. If we were only concerned about one environment, our work would be done. Next, we’ll cover extending that workflow to multiple environments. We’ll follow the common pattern of 3 environments: development, staging, production.

Step 4) Implement Multi-Environment support

view commit

Option A) With GitFlow

This is the approach we recommend, as we enjoy the structure GitFlow provides. However, it does come with the added overhead of your team understanding GitFlow. If you’re not comfortable with this, feel free to use the simpler Option B below.

Here’s an outline of which branches we’d like to deploy to which environments, following GitFlow conventions.

╔═════════════════════╦═══════════════════════╦══╗

║ Branch ║ Environment to Deploy ║ ║

╠═════════════════════╬═══════════════════════╬══╣

║ feature/**, develop ║ dev ║ ║

║ release/** ║ staging ║ ║

║ master ║ production ║ ║

╚═════════════════════╩═══════════════════════╩══╝

If you haven’t already, initialize GitFlow. Then, start a feature branch.

git flow init

## We kept all default options.

git flow feature start multi-environment-support

Update your workflow ( firebase_web.yml ) to utilize GitFlow style branches.

GitHub Workflow w/GitFlow style branches

Option B) Without GitFlow

This approach simply ties a specific branch to a specific firebase project. Still allowing for multi-environment support, but without a more robust branch structure.

╔═════════╦═══════════════════════╦══╗

║ Branch ║ Environment to Deploy ║ ║

╠═════════╬═══════════════════════╬══╣

║ develop ║ dev ║ ║

║ staging ║ staging ║ ║

║ master ║ production ║ ║

╚═════════╩═══════════════════════╩══╝

Now, checkout your develop branch.

git checkout -b develop

Update your workflow ( firebase_web.yml ) to utilize branches.

GitHub Workflow w/regular style branches

Finally

Let’s edit our .firebaserc to include our 3 project aliases, instead of just a "default". This allows us to specify the project during deployment, via the -P argument.

{

"projects": {

"development": "myapp-dev",

"staging": "myapp-staging",

"production": "myapp-production"

}

}

You should be able to push to GitHub and see a successful action now : )

git add .

git commit -m 'Step 3) Initialize CI&CD w/Github Action'

git push

Additionally, any pushes you make should deploy to the correct Firebase project, based on the branch you’re working on ⚡️

Firebase Hosting — Release History

All done!

Congratulations! You’re now ready to maximize your workflow by utilizing automated deployments to multiple environments 🚀🤙🏻