About Talks Articles

Static Site with Hugo and Firebase

4 min read

About a year ago, I decided to abandon WordPress for this blog and switch to Hugo to generate the content and Firebase to host it. How did the authoring workflow change due to this switch?

WordPress is a CMS (content management system) and hence all the authoring workflow happens in a web browser. With Hugo, the process is radically different. As a static site generator, Hugo will construct all the HTML files from every blog entry written in Markdown format, based on a certain template. The huge benefit: all those Markdown files can be stored conveniently in a version control system. The ubiquitous git is a natural choice for doing so.


As the blog author, I’m working on a blog draft at a time. The local git repository lives in my laptop and this is where I keep iterating and editing the said draft. I can use Hugo locally to test my changes until I am satisfied with the draft and ready to have it published. While this example illustrates the use of Hugo, other popular static site generators also use the same principle.

While the content can be published to Firebase using its excellent CLI, a better approach is to have it fully automated. For doing this, first I set up a private repository on GitLab (other services such as GitHub or Bitbucket would work as well) and make it as the remote origin for my local working repository. Every once a while, particularly when I want to publish a new blog post, I run git push to ensure that the two repositories are in sync. Since GitLab offers web-based editing, if I’m on the road and I want to make a minor tweak to my blog content, I can also do that as long as I have some Internet access.

In addition to a remote repository, I also create an automated build job using GitLab CI. Since it is a built-in feature of GitLab, I don’t need to worry of setting up a CI task somewhere else, e.g. on Travis CI. My .gitlab-ci.yml looks like the following:

image: mhart/alpine-node:6.3
  - apk update && apk add openssl
  - wget
  - echo "37ee91ab3469afbf7602a091d466dfa5  hugo_0.16_linux-64bit.tgz" | md5sum -c
  - tar xf hugo_0.16_linux-64bit.tgz && cp ./hugo /usr/bin
  stage: deploy
  - npm install --silent
  - npm run build:site
  - npm run firebase:deploy-ci

GitLab CI uses an in-container build process, which I do like a lot. The first block in the above file basically sets up the environment in a container based on Alpine-based Node.js image and by downloading and installing Hugo on the fly. This step is actually quite bandwidth-efficient, consuming only about 17 MB in total download size. It is far easier than preparing a custom Hugo image to be placed in Docker Hub. As a bonus, it is also easy to upgrade to a newer Docker image and a newer Hugo.

The actual deployment is carried out using Firebase CLI. Since it is based on Node.js, it is also handy to use package.json:

  "name": "",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "firebase-tools": "~3.0.3"
  "devDependencies": {},
  "scripts": {
    "build:site": "rm -rf public && hugo",
    "firebase:deploy-ci": "firebase deploy --token ${FIREBASE_TOKEN}"

The environment variable FIREBASE_TOKEN stores the Firebase authentication token. It is saved as a secret variable.

Using this setup, every single time I push to GitLab, the deployment process is automatically triggered. Usually it takes about a minute for the deploy job to finish. Manual verification via Firebase Console is also rather easy.

With Firebase Hosting, I enjoy the benefit of HTTP/2, full SSL/TLS for custom domain, as well as CDN support for lightning-fast delivery. At the same time, the workflow is smooth and reliable. Since a static site is only a set of HTML pages, there is no need to worry about CMS vulnerabilities. Easy, secure, and fast!

Related posts:

♡ this article? Explore more articles and follow me Twitter.

Share this on Twitter Facebook