How To Add Draft Posts to A Gatsby Blog
Tags: gatsby, react, tutorial, javascript
Published: 2019-05-09 09:25:36

---
title: How To Add Draft Posts to A Gatsby Blog
published: true
description: 
tags: gatsby, react, tutorial, javascript,
cover_image: https://blog.swingpulse.com/static/ba817f63b18df5750b28a5c5b4e77542/ba299/cover.png
---


I need to exclude specific posts from displaying in production in my blog build with Gatsby and mark them as drafts during development. I will describe how to achieve this goal (manually or via an open sourced plugin) so you can do this too in less than 5 minutes. 

This post is a part of «[10 Better with Gatsby](https://blog.swingpulse.com/10x-better-gatsby)» series where I share my personal experience on tuning and tweaking Gatsby. I will post more good stuff about tuning Gatsby. Check it out! 

# The End Result

List of posts in development:

![](https://blog.swingpulse.com//static/76861222a5c825c0cd6efcd47a1a2658/2d6e0/posts_after.png)

List of posts in production:

![](https://blog.swingpulse.com//static/5c42c3fa1986e14b988e19bf6f2365ee/7b2ae/posts_before.png)

## Requirements

- Show all posts in development
- Hide draft posts in production
- Render released and draft posts differently in development
- Mark post as released automatically if its `date` is after build time
- Mark post as released manually in `md` files.

I found a [plugin](https://www.gatsbyjs.org/packages/gatsby-plugin-draft/) but could not achieve everything I needed. Mine open sourced solution can be found here:

[gatsby-plugin-released](https://github.com/rg4real/gatsby-plugin-released)

It allows you to add release functionality via config and skip part of this article. Also there are additional options you can use. Visit plugins README to learn more.

# Overview

**Step #1. Adding new fields to GraphQL**

We will add a field called `released` based on:

- `date` field from markdown file
- `released` field from markdown file
- `process.env.NODE_ENV`
- `timezone`
- build time (a moment in time when the build happens)

Also we will add a field called `releasedNotForced.` Similar to `released` but with `process.env.NODE_ENV`  been ignored.

This step is abstracted into [gatsby-plugin-released](https://github.com/rg4real/gatsby-plugin-released).

**Step #2. Update GraphQL queries to respect the `released` value**

We should exclude drafts from building and displaying.

**Step #3. Update components to render drafts differently.**

To have a nice visual distinction and feel good about it. :)

# Execution

### **Step #1. Adding new fields to GraphQL**

The goal of this step is to add fields to `node.frontmatter.fields` to use via GraphQL. Gatsby offers a special API for this. What we need is to modify `gatsby-node.js` file.

We will add two fields:

- `released` field
- `releasedNotForced` field that act just like `released` but ignores the `process.env.NODE_ENV` variable.

### Why adding two fields?

Just in case you are wondering.

In development mode we may want to force posts to be rendered without editing any GraphQL queries. It is done by forcing `released`  to be `true` based on `process.env.NODE_ENV`. Thus in a development mode we loose the original value we may want to use in a component code to have a visual distinction between drafts and released posts.

The way to preserve this is to always set the `released` field in a markdown file. But it was so nice to have this value be calculated automatically based on `date`.

That is why I've added a `releasedNotForced` property — to preserve that value while forcing `released` to be true.

Remember, if you don't want to mess with your config just use [this plugin](https://github.com/rg4real/gatsby-plugin-released).

Here is a function we use to calculate `releasedNotForced` value.

```javascript
    // gatsby-node.js
    const moment = require('moment-timezone')
    const getValue = ({ node, options }) => {
      const { fieldName, timezone } = options
      if (!node.frontmatter) {
        return false
      }
    
      if(node.frontmatter.hasOwnProperty(fieldName)) {
        return node.frontmatter[fieldName]
      }    

      if (!node.frontmatter.date) {
        return false
      }
    
      const dateNode = moment.tz(node.frontmatter.date, timezone)
      const dateNow = moment().tz(timezone)
      const value = dateNow.isSameOrAfter(dateNode)
    
      return value
    }
```

Then let's add `released` and `releasedNotForced` fields to `node.frontmatter.fields`. What we need is to use the `onCreateNode` function.

```javascript
     // gatsby-node.js
    const onCreateNode = ({ node, actions }) => {
      const MD_TYPE = 'MarkdownRemark'
      const options = {
        fieldName: 'released',
        fieldNameNotForced: 'releasedNotForced',
        timezone: 'UTC',
        force: process.env.NODE_ENV === 'development',
      }
      const { createNodeField } = actions
      const { fieldName, fieldNameNotForced } = options
    
      // Skip modifications for non-markdown files
      if (node.internal.type !== MD_TYPE) {
        return
      }
    
      const value = getValue({ node, options })
    
      createNodeField({
        node,
        name: fieldName,
        value: options.force === true ? true : value,
      })
      createNodeField({
        node,
        name: fieldNameNotForced,
        value,
      })
    }
```

## **Step #2. Update GraphQL queries to respect the `released` value**

We need to exclude drafts from a build step in file `gatsby-node.js` and respect the `released` value from blog pages such as `index.js.`

In both cases the query will look something like this. Pay attention to a filter property.

```javascript

    const query = graphql(
        `
          {
            allMarkdownRemark(
              sort: { fields: [frontmatter___date], order: DESC }
              filter: { fields: { released: { eq: true } } }
            ) {
              edges {
                node {
    							id
                }
              }
            }
          }
        `
      )

```

## **Step #3. Update components to render drafts differently**

This step is totally up to yours component tree. The key point is to request necessary fields via GraphQL query.

```javascript
    const query = graphql`
      query {
        allMarkdownRemark(
          sort: { fields: [frontmatter___date], order: DESC }
          filter: { fields: { released: { eq: true } } }
        ) {
          edges {
            node {
              id
              fields {
                slug
    		released
    		releasedNotForced
              }
            }
          }
        }
      }
    `
```

# Conclusion

So we have a single GraphQL query for production and development, `released` field is calculated automatically and draft posts can be rendered differently. Cool!

And be warned! There are drafts in my «[10x better Gatsby](https://blog.swingpulse.com/10x-better-gatsby)» series! :) So go check it out to stay tuned!