Hiding draft blog posts using Gatsby.js

December 06, 2020

Update 2021: Another obvious way of doing this is using git branches, duh! You can create drafts on branches and merge them in when ready. This is an even easier way to work with drafts. I also plan to change the code snippets below from images to text so folks can copy/paste and more importantly, make it accessible.

If you’ve tried to use Gatsby.js for blogging, there’s a great template available to get started. All you have to do is follow the directions on this page and you’re off!

The problem is, you’ll quickly learn you can’t create a draft post, which is important for blogging. This functionality is handy if you want to work on a post over the course of a few days, commit your changes and don’t want folks to see things in-progress.

You can certainly use a new branch, tell your build process to ignore it, but I’d prefer to put my posts in a /drafts folder and use that to hide posts that aren’t quite ready. Controlling this from the app means my build can just focus on building and not worry about blogging features.

Let’s get started!

Making our changes

First, what are our goals?

If a post is under /drafts…

  1. We don’t want a link to show on the main page.
  2. We don’t want the page to render if someone were to guess the URL.

To accomplish both, we need to detect and flag the draft nodes in gatsby to indicate they’re a draft while processing the markdown. Once this is accomplished, everything else can simply work to filter out the nodes/posts and prevent them from showing up.

Create your directory

Move or create a test post under /content/blog/drafts/. From here on out, any posts under this folder will be visible locally but they’ll never show up as being available in Production.

Modify the config

Open up gatsby.node.js in your favorite text editor.

Production Only

We only want this to hide in production so we can view the post locally and try it out ahead of time.

Add the following variable somewhere at the top of this file:

Is production code

Flag the drafts

Find the exports.onCreateNode function. When a node is created, this area sets up the slug field for use later on. Insert the following (I’ve omitted neighboring code for clairity).

New field code

Finally, at the bottom of this file, find the Fields schema and add the new field. This sets up the graphql types for us which we need to query.

Types change

Prevent page creation

Now that we have the flag set, we need to use it to filter the drafts. We’ll first filter out the posts that are drafts so Gatsby won’t create a page for them. This prevents folks from guessing the URL of drafts and peeking on your awesome content still in progress.

Find the exports.createPages location in this file and locate the code where we iterate over the posts. Add the if(posts.fields.isDraft... line to skip adding the post if it’s a draft and we’re on production.

Filter out the posts from being created

Hide the links

Now that the pages won’t be available, we need to filter them from the main page so they don’t show up as links. To do so, open src/pages/index.js and filter out those posts as shown below:

Filter the posts on the index page

Don’t forget to add the type to the graphql logic so this field is available.

Add the fields to the graphql

Testing it all out.

Testing is pretty simple. Just run the blog locally, ensure you can view the post on the main page as well as the contents.

To test the production side, you can deploy or flip your environment variable to indicate production, and you should not see any draft posts.

That’s all there is to it! To make the drafts public, just move the post out of that folder.

If you need the raw text/code, you can check out the gist here


Hi there. I'm Lee McKinnon and I live in the Boston area. I build software for Investment professionals and poke around all things tech. You can follow me on Twitter