How to use Jekyll SSG with Headless CMS

Katie - Sep 8 '21 - - Dev Community

Architecturally, getting API-based headless CMS to work with the Jekyll SSG is a bit nuanced.

I believe that’s because Jekyll is old and wasn’t build with 3rd-party headless CMS in mind.

The TL;DR, from what I can tell, is that even though you don’t commit your data into Git, you trick Jekyll into thinking the data was there by downloading your content from an API into your input filesystem at the last minute before jekyll build gets to it.

Technically, a last-minute download like that is all 11ty or Gatsby is doing, too … but they take care of it by allowing you to write configuration files for them that tell them to do this as part of the “build” process.

Jekyll’s build command seems too naive to know about the idea of the files it needs not already being in the filesystem, so you have to hand-write more code (or at least install and hand-run more plugins) to perform the download than you might with another SSG.

(Pssst – this is why I love Eleventy. Same great Liquid templating language as Jekyll. Simpler fetching of API-based input data.)

How does Jekyll work?

Fundamentally, here’s what you “do” when you build and deploy a static web site using a static site builder like Jekyll and a static web host like Netlify, GitHub Pages, Vercel, or AWS S3:

  1. You put a bunch of data files you’d like to transform into HTML, and Jekyll SSG configuration instruction files, into a folder on a computer.
  2. You install software onto the computer so that it can execute code written in the Ruby programming language.
  3. You install extended command sets / modules / libraries (a.k.a. “gems”) to the Ruby programming language onto the computer, one of which is called “Jekyll” and whose sole purpose is to serve as a static website generator, and which comes with a command called build to make it do its magic.
  4. Using the computer’s command line’s “present working directory” focused on the folder in which you put a bunch of files at step 1, you execute a “shell command” (or you execute a command to run a series of shell commands, known as running a “shell script”) that includes summoning the “build” command of the Jekyll plugin to the Ruby programming language.
    • A great reason to use an entire shell script is when you’d like to run a separate program that tidies up the files in step 1 before running jekyll build against them.
    • Example #1: Replacing ENV_GOES_HERE in a configuration file with an actual secret password stored in one of the computer’s “environment variables” or in a file saved on the computer called .env
    • Example #2: Emptying out and repopulating the files in a folder called _data by running code that downloads data from a 3rd-party headless CMS tool’s API (since the jekyll build command isn’t really optimized for doing that the way the build commands of newer static site generators are optimized to allow).
  5. You find the sub-folder of output HTML files generated by Jekyll and move them into a folder designated by a static web host (or, with a web server installed on the computer from which you did the “build process,” you point the web server to this folder and run it).

In the real world, you may or may not use your own computer for any of this. Often, you borrow someone else’s (Netlify’s, Vercel’s, AWS Amplify’s, Heroku’s, GitHub Pages’, Cloudflare Pages’, etc.) computer(s) with Ruby & Jekyll preinstalled to do the “build” steps.

All you have to do is kick off step 1 by sending your configuration & data files to their computer. These days, you do this by tracking your files with software called git and uploading them to a major cloud host like GitHub, BitBucket, or GitLab.

The computer you borrowed for “running the build process” reads your configuration files and does all the hard work of steps 2-5.

When all of the data you’d like to transform into HTML exists as part of your Git-tracked folder, the only things you need to learn are the peculiarities of structuring your files to that the jekyll build command is happy. The internet is full of tutorials that can teach you that.

However, if most of the data you’d like to transform into HTML lives out on the internet, in a 3rd-party cloud-hosted “API-based” content management system (like Sanity or Contentful), you also have to learn how to structure your files so that step 4 downloads your data into an appropriate part of your folder structure before jekyll build runs against it. That’s what we’ll talk about in this article.

Making theme architecture choices

Jekyll is highly opinionated about the file and folder structure from which it’s willing to build output HTML, so you’re pretty much limited to:

  1. Downloading your data into JSON-formatted or YAML-formatted .json or .yaml files in a subfolder called _data (easier) and building the templates in your _layouts subfolder to work off of site.data instead of page properties (harder).
    • This is the approach Contentful CMS advocates when they suggest running jekyll contentful before running jekyll build (examples here).
    • Personally, I haven’t gotten it working smoothly on my local machine with a .env file storing my API key yet, but I suspect it would probably work on a machine where actual environment variables were set, since that’s what their Jekyll plugin expects.
  2. Downloading your data into .md files that contain nothing but YAML-formattted “front matter”, saving them into subfolders where Jekyll traditionally expects to find such files (harder) and building the templates in _layouts more traditionally (easier).
    • This seems to be what the themes do that Stackbit publishes for multiple static site generators do whenever you choose “Jekyll” and an API-based CMS.
    • I haven’t done this from scratch, but I like idea of not having to rewrite the layout templates of themes that leverage Jekyll’s native page loop (perhaps having been designed for traditional .md-based data files).

Digital garden notice

Sadly, I don’t yet have an amazing “minimum viable build” codebase of the two approaches. I’ll come back and edit this post if I make one!

I hope, however, that you’re able to use this knowledge to better understand codebases you encounter when you search for “sanity jekyll” or “contentful jekyll” or “jekyll headless cms” and find other people’s “starters” you need to reverse-engineer.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .