Skip to main content
Ministry of Intrigue Ministry of Intrigue
  1. Dispatches/

Changelog: Scheduled Posts in Jekyll

·691 words·4 mins
Articles meta development jekyll octopress

I do so love to tinker…

One thing that has annoyed me about using a static site generator for my blog has been the lack of scheduled posts. It’s a feature I relied on quite a bit back when I used Wordpress, and also when I built my custom Django CMS. However, with a static site generator, automating posts isn’t just a matter of flicking a switch, as there is not a database that is driving the site display on a per-request basis. It was frustrating, but I wrote it off as a cost of all the other benefits I enjoyed from using Jekyll.

As I’ve been writing quite a bit more lately, and since I tend to write posts in quick succession, I’ve been doing massive batches of posts that all publish at the same time. That’s not ideal for a reader, so two weeks ago, I dusted off the idea of scheduled posts and set my mind to implementing them.

As it turns out, there are variety of ways for scheduling posts in Jekyll. After all, it has a built-in configuration setting to disallow future posts, so preventing posts from appearing early is as easy as setting future: false in your _config.yml file. Once you’ve done that, it’s just a matter of having your site generate on a scheduled basis.

Of course, scheduled generation means that you have to be careful not to accidentally deploy draft posts, or structural changes, while they are in progress. Jekyll, especially when using the Octopress gem, has pretty good support for drafts, and you can even implement complex workflows to manage the process. However, I found that scheduling generations based on an ad hoc process was a little more cumbersome than I wanted, and ultimately I wanted to avoid scheduled posts being dependent on my local machine. After all, my primary machine is a Macbook Pro, and I didn’t want my publishing schedule to be impacted if I was traveling or otherwise offline.

The solution was pretty obvious: I do scheduled generations on my server. After all, I’ve maintained a Linode VPS for several years, and it’s always online and available. Since my site source is maintained in a git repository, it’s also easy to handle versioning across multiple machines. From there, it’s a simple task to have cron regenerate the data and deploy the updated version of the site.

My current process for posting is now:

  • Draft a post (usually in Ulysses)
  • Add it to the _posts directory, editing the date setting to the scheduled posting time.
  • Preview the post using jekyll serve --future true to check for any formatting errors.
  • Commit to the master branch, and push to my remote repository.

After that, the cronjob handles the rest. Once per hour, cron:

  • Pulls latest changes from the master branch of the git repository.
  • Runs jekyll build.
  • Runs octopress deploy.

And bam: Scheduled posts in Jekyll. In fact, every post you’ve read on this site for the past week has been published asynchronously via this method, including this one. I compose multiple posts at my leisure in the evenings, schedule them for publishing, and then go about my business.

Since the cronjob uses only the master branch, I’m free to test structural site changes in a separate git branch and then merge them to master when I’m ready for them to be deployed.1 The whole process is easy and automated, which is exactly what I was looking for in a solution.

Sure, it may be a bit nerdy and convoluted for an average user, but I’m very happy with this implementation, and it scratches a mental itch. The joy of problem solving, and that of creative expression, is what’s kept me going with this site for the last eleven years. When it stops being fun, that’s when I’ll stop doing it, but for the time being, I’m having a blast posting here again. This process enables me do that without dropping a tossed salad of posts into your feed reader a few times a week.

So, you know, you’re welcome. 😉

  1. Which is really what should be done in the first place. ↩︎