In this blog post, I’ll show you how to setup your Hugo blog for automatic deployment to Google Firebase Hosting .

I’ll assume that you already have

  • a Github account with a repository setup to sync your blog
  • setup firebase hosting via firebase init hosting to publish the blog via the CLI

We will add a Github Actions workflow for CI/CD, so the blog is automatically built and published whenever we push to it.

If you setup your Hugo blog to host in Render, CloudFlare Pages, or Azure, they should have already setup a Github Action workflow using a framework/build preset. In that case, you do not need to do anything extra. If, like me, you use Firebase which is framework-agnostic, then there is an additional step after you finished setting up hosting with its CLI. There are some hiccups from the Firebase CLI and I think that my bad experience motivates me to write a post to share all my mistakes, so you don’t waste as much time as I did!

What’s the problem?

When some steps during firebase init hosting asked if you want to

  • setup automatic builds and deploys with Github (Q6-9 in official doc)
  • authenticate your Firebase account
  • setup a Github workflow

I made the assumption that they have setup CI/CD. In fact, firebase init hosting merely takes care of its own hosting by creating firebase.json and .firebaserc files to store configuration and project settings. Nothing about github is done!

Since Firebase is framework-agnostic, we need to perform an additional step after hosting is configured. Here’s how:

The right steps

We need to run firebase init hosting:github after firebase init hosting is completed.

note: When I setup a new Hugo blog, I thought I could shoot one bird with 2 stones just by doing firebase init hosting:github. This will fail as it needs to look up firebase.json and .firebaserc (created by firebase init hosting) for project information to work on.

  1. Specify your Github repository

  2. CLI will automatically creates a Firebase project Service account with deploy permission, and authenticate with GitHub to upload this service account JSON to the repo’s secrets store.

  3. The CLI now detects I’ve added a predeploy script "predeploy": "hugo", to firebase.json , and prompts me to use it in the new workflow.

    note: This is the place where we should specify the workflow to do hugo to build our files. Don’t believe it! Just press ENTER to accept the default. I notice that it really doesn’t matter what you input, as it will default back to building for node.js. Don’t worry, we will edit this value in step 5. predeploy

  4. Say yes to the remaining options. It will finally create 2 yaml files for both merge (firebase-hosting-merge.yml) and PR (firebase-hosting-pull-request.yml) workflows in the .github/workflows/ folder. These will automate build and deploy whenever there is a push or pull request in your Github repository. Both use the official FirebaseExtended action to deploy.

    Let’s look at firebase-hosting-merge.yml. What the script does is

    1. checkout the repo files
    2. build (using npm)
    3. deploy to Firebase
    name: Deploy to Firebase Hosting on merge
    'on':
      push:
        branches:
          - main
    jobs:
      build_and_deploy:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - run: npm ci && npm run build
          - uses: FirebaseExtended/action-hosting-deploy@v0
            with:
              repoToken: '${{ secrets.GITHUB_TOKEN }}'
              firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_YOUR-FIREBASE-PROJECTID }}'
              channelId: live
              projectId: YOUR-FIREBASE-PROJECTID
    
  5. Since it ignores what we enter in step 3, we will edit the workflow file to take care of Hugo builds

    1. We might be tempted to just swap out the run: npm ci and replace it with run: hugo to build our files and call it a day. I did that and it was not still missing parts!

      A proper workflow is

      1. check out repo files
      2. setup the Hugo environment
      3. Build Hugo site
      4. Deploy

      Clearly what’s missing from Firebase CLI’s default workflow is 2 and 3. So let’s patch our yml with the following

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2.5.0 # Action to set up Hugo environment
        with:
          hugo-version: 'latest' # Specifies the Hugo version to use
      
      - name: Build Hugo site
        run: hugo --minify # Runs the Hugo build command with minification
      
  6. Now recall how you acquired your Hugo theme. You can check its readme or github.

    • Is it by git clone? Then it’s ok, please jump to the next step.
    • Is it by using a submodule? (check the existence of .gitmodules file in your project root folder) If so, make sure you specify the yml with
      - uses: actions/checkout@v4 # Updated to v4
        with:
          submodules: true # Added for Hugo themes that are Git submodules
      

    This is another mistake I made. Without this, the checkout process will not fetch layouts and css from the theme’s original repo, and the build will not complete. My old process was building and deploying locally (which contains all the submodule theme files) so this is new to me Worst yet, Github Action status will show everything green and checked, with the errors hidden as mere warnings. For your first few pushes, make sure to go to Github/Actions/click the workflow run, click build_and_deploy job and expand Build Hugo Site to check if the files are successfully built. You can see that the layouts are missing. If you just glance at the top level Action status, everything looks good. action status

  7. For your theme, does it use SCSS and SASS? Again confirm with its readme. If so, make sure extended is added to the Setup Hugo step, like

    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2.5.0 # Action to set up Hugo environment
      with:
         hugo-version: 'latest' # Specifies the Hugo version to use
         extended: true # <--- ADD THIS LINE TO USE THE EXTENDED HUGO VERSION 
    
  8. Commit and push the new files to your repo.

  9. Let’s test editing some .md files in your desktop and push to Github. Verify that the updates are properly deployed to Firebase.

Now we’re all done and we can use both desktop or mobile Github clients to sync our blog to Github, wherever we are.