Schedule Netlify Builds with GitHub Actions

Janne Kemppainen |

Would you like to be able to schedule the blog posts for your static site into the future but don’t want to use up all of your free Netlify build quota? In this post we’ll create a GitHub Actions workflow that triggers a site rebuild when a post has been scheduled to be published.

In general, scheduling blog posts can be a nice way to spread your content over a time period to make your blogging feel more consistent even if you were on holiday. Another use case could be to schedule the posts to be published at the same time with your YouTube videos.

With a static site generator this is not as straight forward as you don’t have a database and an active server that would handle everything. The easy solution is to just trigger the site build periodically but the more often you build the more build minutes you’ll be using unnecessarily. If you only publish on Mondays at 6 pm. then maybe that’s not too bad but if your publish times are all over the place then you should probably look for optimizations.

In the previous post I implemented a custom GitHub Action that can read the front matter of each blog post in your content directory to see if something has been scheduled.

I tried to combine the deployment with the official workflow from netlify/actions but I couldn’t get it to work. So I used the Netlify build hook directly with the run keyword. This even makes the job execute a lot faster because the runner doesn’t need to download the Docker container that the official action was using.

For the TL;DR people, just save this file as .github/workflows/schedule.yml in your site repository, create a deploy hook on Netlify, store the URL as NETLIFY_BUILD_HOOK in your repository secrets, and call it a day:

name: Schedule post

on:
  schedule:
    - cron: "0 * * * *"

jobs:
  schedule:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - uses: jannekem/[email protected]
      with:
        interval: 60
        content_directory: content
      id: publish
    - name: Trigger build
      if: steps.publish.outputs.is_scheduled == 'true'
      run: curl -X POST -d {} $NETLIFY_BUILD_HOOK
      env:
        NETLIFY_BUILD_HOOK: ${{ secrets.NETLIFY_BUILD_HOOK }}

For those that want the details, let’s continue!

Quick intro to Actions

If you didn’t already know it, GitHub Actions is a way to automate things in your GitHub repository. With it you can create workflows that can do things with your repository and react to different kinds of events.

Each time an action triggers it starts a virtual machine and starts executing the steps defined in a workflow file, just like the one that I showed above. The workflows are saved as YAML files inside the .github/workflows directory.

Workflows can combine a number of different action steps and command line calls to create complex behavior. The actions can be triggered for example when new commits are pushed or when an issue is opened, or on schedule like in our case.

Using actions is free for public repositories and you get a certain number of actions minutes for private repositories each month.

For a more detailed introduction be sure to check out my Gentle Introduction to GitHub Actions.

The workflow file

Take a look at the workflow file again. First you have to define a name for the workflow. I’m calling this “Schedule post” but you can call it whatever you want as long as you have something there.

The on section defines the schedule for triggering the workflow using the cron syntax. Here you can set the schedule that you want. You could run the check every hour like I do or maybe do it just once a day at a certain time. If timing the posts is critical you could run it even more often such as every fifteen minutes. Note that the shortest interval you can use is 5 minutes.

Use the ubuntu-latest as the runner type.

The first step in the steps section checks out your repository so that the files are available to the runner.

The second step uses my custom action that determines if a post has been scheduled. It accepts two configuration parameters:

  • interval defines the amount of minutes that should be included in the check. This has to coincide with your cron configuration. If the workflow runs once an hour the value should be 60, if it runs every fifteen minutes then naturally 15, and so on.
  • content_directory is an optional parameter that defines where the action should look for the Markdown files. The whole repository will be searched if left empty.

If you’re using the Hugo static site generator like I am then the action should just work with your existing content. It only needs the date parameter to be set in the YAML front matter of each post, and it needs to be parseable with the moment.js library.

The final step uses a simple curl request on the command line to trigger the site build when needed. The if conditional checks the output from the previous step and executes the step only if a post has been scheduled. Otherwise the step is just skipped and you don’t consume your precious Netlify build minutes!

You need to store the Netlify build hook inside the repository secrets in GitHub as NETLIFY_BUILD_HOOK. Go to the Settings tab on your repository, choose the Secrets section and click “New secret” to create the secret.

To obtain your build hook you need to sign in to your Netlify account, choose the site you want to deploy and select “Build & deploy”. There you can add a new build hook in the Build hooks section. This will give you the hook URL that needs to be stored in the repository secrets.

Scheduling your posts

Now that you have the workflow all ready and configured scheduling the posts is super easy. Just write your posts normally and when you remove the draft configuration in the front matter also remember to set the date parameter to the time and date when you wish the post to go online.

Then just sit back, relax and watch your posts dripping online one by one without you having to intervene! This will work wonderfully if you write many blog posts at once but don’t want to dump them all at the same time.

It seems that the GitHub cron schedule is not guaranteed to start at the same minute as it was configured. There must be some balancing going on on the GitHub side because my jobs are consistently triggered four to five minutes after the configured time. This is quite understandable if you imagine the sheer amount of jobs that must have been triggered to run on even hours. Just take this into account when you set the scheduled time.

Conclusion

I have configured the same workflow for this site and even used it to publish this post. This should give me some flexibility to time the posts without having to do things manually.

As always, I hope this has post has been helpful to you. Hit me up on Twitter if you’d like me to write a post about something that you’d like learn more about. Until next time!

Read next in the Blog with Hugo series.

Add an RSS Feed to Your Hugo Blog

Discuss on Twitter

Subscribe to my newsletter

What’s new with PäksTech? Subscribe to receive occasional emails where I will sum up stuff that has happened at the blog and what may be coming next.

powered by TinyLetter | Privacy Policy