Firebase hosting: Deploy multiple sites into same project using Cloudbuild

sujesh thekkepatt
7 min readJan 6, 2021
Photo by Alex Motoc on Unsplash

Recently we had to switch from Netlify to Firebase for React hosting. Going from Netlify to Firebase, not gonna lie, is a little painful process. Netlify got a huge benefit of time reduction and a simplified hosting process. But that does not mean Firebase is hard, it’s just that I was using Netlify for a long time. And we know the nuances and etc.

The main requirement for us is that we are using a tag-based release flow. We have only one main branch (not separate branches for staging and prod, dev) from where we tag releases for staging and production. So the simple workflow for adding a feature f1 is, create a branch f1 from the main branch, work on it, merge it back to the main branch. Now we have working code on the main branch and we create new tags for staging and if that found working as expected we will create a release for production.

So whenever we create a release for staging we need to deploy a staging url with the latest code. Similarly for production.

But the thing is that both Netlify and Firebase does not support this out of the box. In Netlify if you have a separate branch, say, like production, staging then you can enable branch deploys and associate the branch url to a subdomain and use it as it is. That serves good. But still, no direct tag-based release support 😵. On the contrary, we cannot guess Firebase preview URLs (still on beta) since they contain a hash every time. Their format is like branchname.hash-value.app-url. Also no direct tag-based release support. Their built-in GitHub CICD solution works fine for simple scenarios but not for some custom solutions.

Hey but this not end of hope. Ideally, this is a situation where we have to use some external build systems as there is a custom workflow. The above-mentioned flow can be set up using easily with GitHub actions and Cloudbuild.

Cloud build and GitHub actions are both my favorite systems. We can implement custom logic that spans across multiple build steps. Here I am going to use Cloud build. The same can be achieved through Github (I suppose).

Cloud build is a fantastic platform that enables us to build our cloud-native solutions. So given below some steps we are going to perform,

  • Go to cloud build add the repository
  • Set up a trigger that runs whenever a tag is created for both staging and prod
  • Now in the regex section add a regex that will correspond to the tag name. Given below my regex which supports semantic versioning.
  • Clone the repo and run firebase init hosting
  • Run firbase login:ci command and save the access token which is later used to deploy
  • Setup deploy targets since we need to set up multiple hosting
  • And push a tag

So let’s dig deeper into the following steps. If you got a rough idea and need to try your own go try and build it. Actually, the above bullet points are the TL;DR of this blog.

Now if you are with me, let’s start. 😄

Go to the Firebase console and create two sites. Firebase supports multiple sites option and I already said earlier they also support preview URL which is currently in beta. So having said that I created two websites as shown in the figure,

Now let’s download and install Firebase CLI.

npm install -g firebase-tools

This will download and install the Firebase CLI tools and now we need to login and initialize it. On your terminal type the following,

firebase login 

This will open up the browser and do the auth. Now we have successfully authenticated with firebase and now let’s init the project repo,

firebase init

This will ask you a couple of questions. Remember to choose the hosting option and follow along with the questions. Don’t set up GitHub as we will set up it in cloud build.

Now based on your input firebase.json and .firebaserc files will be created in the root of your project. firebase.json contains some config information related to your project. Now we are halfway through setting up firebase for the deployment.

In firebase, you can setup deploy targets. Deploy targets are nothing but some unique identifiers that we give to identify uniquely each resource. This is come in handy when you deploy multiple sites and programmatically apply some config specific to one.

In our case, we will be using it to deploy individual services when something happens at Github. ie When production and staging releases are cut. In order to set up head over to your terminal and type the following. Remember to replace it with your resource's name.

firebase target:apply hosting prod-version prod-cloudbuild
firebase target:apply hosting staging-version staging-cloudbuild

These commands will modify your .firebaserc. You can check the targets using the below command.

firebase target

Given below the .firebaserc file after applying targets,

Now you can see the configured targets. Now we modify the firebase.json file and add the target configuration to hosting. Given below the configuration as per my project,

You are still with me, right?

okay, in that case, we need a ci token from firebase. To get that token type the below command on your terminal,

firbase login:ci

This works similarly for login but at the end of the process, it will create a token. Please take care of it. We will be needing it during the cloud build setup. Now we have done the firebase part.

Let’s head over to cloud build. We have to enable firebase and cloud build APIs. Check out this link from where you can easily set up permissions and APIs. It also explains the steps to build a firebase container image which we will be using in the cloud build. I am not explaining them here as it is self-explaining.

Now go to the trigger section and click on the manage repositories button. Once you add the desired repository create a new trigger. In the event, the option selects the new tag option. Now in the tag section, you can setup a regex for which only the trigger will fire.

I have created a regex that you can use to experiment here. It’s nothing but a simple regex (use caution when using it in production) that matches staging/v0.0.1 ans staging/v0.0.2-alpha etc. Now choose the file type option to cloudbuild configuration file. Now in the advanced section, you can see substitution variables.

Substitution variables are nothing but kind of environmental variables that will be available to the containers running during the build steps. We can also override the values using the cloud build config file. This way you have more flexibility to modify behaviors.

A word of caution: We will be using substitution variables for injecting the FIREBASE TOKEN for deployment purposes. However this is not so “secure” practice. If your system need advanced cryptographic functionlities to encrypt, setup the ‘token’ using secretEnv.

Now add the configs as shown in the figure. You can choose whatever name you may like. Replace the values as per your setup.

Now create a cloudbuild.yamlfile on your root project folder. Given below a sample cloud build config file replace it with your values.

steps:
- name: 'gcr.io/cloud-builders/npm'
args: ['install']
- name: 'gcr.io/cloud-builders/npm'
args: ['run','build']
- name: 'gcr.io/$PROJECT_ID/firebase'
args: ['deploy', '--project=your_firebase_project_id', '-- only=hosting:$_FIREBASE_TARGET','--token','$_FIREBASE_TOKEN']

Now push to GitHub and tag a release. Given below the screenshot from the cloud build console. I have created two triggers separate for prod and staging. Since I have used the substitution variables I can reuse the cloud build config file across different environments.

Voila.

We can see a deployment trigger in the cloud build console. After a successful build go to the firebase console and you can see the site build information there. Now create another cloud build trigger for prod release and boom. You have working ci/cd integration with cloud build using GitHub for prod and staging in the same project.

Although we used a tag-based approach you can also use the methods to set up a multi-branch environment.

We saw how to set up a tag-based staging and production environment in Firebase with Cloudbuild and Github. Cloud build is an awesome tool. If you haven’t checked it out yet do check it out.

Happy hacking!!

If you like my work and want to support it, buy me a cup of coffee!. Thanks.

--

--