Scheduling future publication with Hugo, GitHub Actions and Pages

This site is a static site, pre-built with Hugo and uploaded to GitHub Pages. Static sites do not appear to lend themselves to dynamic functionality, like scheduling posts for later, automatic publication. This is what I believed; I had to be there, at the keyboard, bashing out commands, to upload a new version.

But with a little creativity, it can be done.

A couple of weeks after I started to use GitHub Actions to publish this site, I had three or four posts half-drafted (a result of my goal to post smaller things, less often). I wanted to get them finished, but I thought it’d be good to publish them over time rather than all at once. Idly, I wondered whether Hugo could schedule posts, and thought, “no, of course not, I have to run Hugo”. It was then that it hit me that I’d just got “running Hugo” automated within an Actions workflow. And that Actions must have a way to schedule regular execution of a workflow. A plan for scheduled posts was born.

I’ve been using this setup for a couple of months now to schedule publication. It’s simple and reliable. This post shows how to set this up for any GitHub Pages site that uses Hugo. While this post talks specifics for this setup, I expect the general idea can be made to work with any CI/CD and static site builder.

The outline for this is:

  1. Set up a GitHub Pages site to be built using Hugo and published nightly using GitHub Actions.
  2. Show how to write a Hugo post for future publishing. It’ll be caught and published during the nightly scheduled build, but not before.

Let’s get started.

Publishing to GitHub Pages using GitHub Actions

The first step is to create a Hugo website, commit it to Git and upload it to GitHub. I’ll assume that’s already done. If your site is currently using the gh-pages workflow with Hugo, following the steps in this post will convert it to a GitHub Pages flow using GitHub Actions. If you are starting from scratch, we’ll go through getting from a newly pushed Hugo site in a repository to a site published on GitHub’s free domain, github.io.

Regardless, your site should have a main branch that is the Hugo “source code” version of the site. We’ll create a GitHub Action that executes the Hugo build process and uses its output to publish to the GitHub Pages site for the repository.

The use of the GitHub Actions workflow to publish to GitHub Pages, rather than the older gh-pages-branch-based publish workflow, is the key to scheduled posts. The Action can be scheduled to run nightly, which enables automatic publishing of new content.

Create the workflow

First, visit your repository’s Settings page, then hit the Pages section in the left navigation. From there, set the Build and Deployment source to GitHub Actions.

Next, go to Actions in the top navigation for your repository, and hit New Workflow in the top left.

Search for hugo and select the Hugo (by GitHub Actions) workflow. Hit Configure.

This will open the workflow’s default YAML configuration. We want to make two changes:

  1. Add a scheduled build to build the workflow every night.
  2. Optionally, change the version of Hugo.

Run the workflow every night

We can set a schedule using cron notation. This is set in the on field of the workflow, which controls when the workflow is run:

on:
  # Runs on pushes targeting the default branch
  push:
    branches: ["master"]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:
  
  # Daily publish at 05:00Z to allow for scheduled posts
  schedule:
    - cron: '0 5 * * *'

This is entered in the workflow configuration screen that appears after selecting Configure for the Hugo workflow:

It can also be set up later, by editing the hugo.yml file that will be added to the .github/workflows directory of the repository.

Customise the Hugo version

Further down the workflow’s YAML, the version of Hugo to use is defined. Any released version of Hugo can be used. Just update HUGO_VERSION:

Again, this can also be changed later for newer Hugo releases, by editing the .github/workflows/hugo.yml file that will be added to the repository.

Finishing up the workflow

Hit Start Commit in the top right to commit the workflow to your GitHub repository. Commit the file to the main branch with a suitable commit message.

Now, both whenever you push a commit and each day at 05:00 UTC, the site will be built using Hugo and published to the GitHub Pages URL set up for the site.

Using from Hugo

This is the simple part. Just ensure the date is set in the future, and ensure that draft is set to false in your frontmatter:

---
title: "A post for the far future"
date: 2100-01-01
draft: false
---

Alternatively, the publishDate can be used to hold up publication even if the date field is in the past:

---
title: "Today's post will appear in the far future"
date: 2023-04-16
publishDate: 2100-01-01
draft: false
---

Commit and push to GitHub. The site will build immediately, but the future post will not appear. Come 2100-01-01 at 05:00 UTC, it’ll appear on the published site after the scheduled build.

And we’re done 🌟

← Older
Twenty years
→ Newer
Neovim journey: using LSP without any plugins!