Automate Firebase 🔥 hosting with Github Actions

May 23, 2020

UPDATE 01/21/21: Using the firebase init command you can now automatically set up deployment from Github through the CLI and you shouldn’t have to follow any of this tutorial. Try that first. It should set up an action for merge and one for PRs.

This is a tutorial for quickly setting up a Github action to deploy a site to Firebase hosting. This would include sites built with Vue, React, Gatsby, the Next.js static generator or any other client-side site. In a few minutes you can be set up so every time you push code to master it will automatically be built by Github and deployed to Firebase. I’m going to assume you already have your code on Github and a firebase project setup. If your project doesn’t have a firebase.json file in the root directory, or if that file doesn’t have a hosting section you may need to run firebase init. Also make sure you have a .firebaserc file with your project ID or the deploy function won’t work. If you run firebase init and follow the instructions to set up hosting both files should be created for you.

Here’s an example of what the files should look like:

// .firebaserc
{
  "projects": {
    "default": "project-id"
  }
}

project-id should be replaced with your project ID from the firebase console. This is all done for you if you use the firebase init command from the CLI.

// firebase.json
{
  "hosting": {
    "site": "site-name",
    "public": "dist",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

site-name should be replaced with the name of the site you want to deploy to (…if you want to deploy to a custom named site you created in firebase console. If you just want to use the default site then you shouldn’t include the site key), and dist should be the directory your site gets built to. Usually it’s either dist or public.

Next you’ll need to create a file called main.yml at the path .github/workflows/. That file should have these contents:

name: Build and Deploy
on:
  push:
    branches:
      - master

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
      - name: Install Dependencies
        run: npm install
      - name: Build
        run: npm run build
      - name: Archive Production Artifact
        uses: actions/upload-artifact@master
        with:
          name: dist
          path: dist
  deploy:
    name: Deploy
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
      - name: Download Artifact
        uses: actions/download-artifact@master
        with:
          name: dist
          path: dist
      - name: Deploy to Firebase
        uses: w9jds/firebase-action@master
        with:
          args: deploy --only hosting
        env:
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}

The things you may need to change here are any reference to dist, change to whatever your build script outputs the final code to, and the npm run build line can be changed to whatever your build command is. Note: you can easily swap npm out with yarn, which at this time is available globally on the build environment.

This file basically runs two separate jobs: one to build the site files from your source code, and one to take that artifact and deploy it to Firebase hosting.

The final piece you need here is to add your secret Firebase token to Github so it has permission to deploy the site for you. To get this token run firebase login:ci in your terminal and copy the code generated. You’ll paste that code in the settings of your Github project on the secrets page. Create a new secret with the name FIREBASE_TOKEN and paste the code you got from your terminal.

Now you can commit both files and push to Github and the Github action will take care of the rest. After you push you should be able to see the progress in the actions tab in your Github project.


Written by Matt Gregg, a UI engineer who lives and works in Minneapolis, MN

Have something to say about this post? Tweet at me

matt@codegregg.com