Using Hashnode as a Source for Gatsby
Tags: gatsby, hashnode
Published: 2021-11-06 18:11:15

---
title: Using Hashnode as a Source for Gatsby
published: true
date: 2021-11-05 17:51:49 UTC
tags: gatsby, hashnode
canonical_url: https://www.alexhyett.com/hashnode-as-gatsby-source
cover_image: https://www.alexhyett.com/static/9633db6f0cdbf28ef29499333cb8f5bd/gzPGA7FJ3A.png
---

I have done quite a few website migrations over the years. My blog like many first started out on WordPress. After several [attempts at optimisation](https://www.alexhyett.com/speed-up-wordpress), I ended up generating a static version of my WordPress website.

On my static site generation journey, I discovered Gatsby.js and completely redesigned my website around it. However, writing posts locally in markdown has its own downsides and lacks the discoverability you get from blogging on Hashnode.

So I decided to move my blog posts over to Hashnode but I still wanted my posts to appear on my [main blog](https://www.alexhyett.com/blog).

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#migrating-the-blog-posts)Migrating the Blog Posts

The first step was to import all my blog posts to Hashnode. There are a few methods you can use to import your blog posts.

![Hashnode import methods](https://cdn.hashnode.com/res/hashnode/image/upload/v1636016684113/yDQESA6zu.png)

I decided to use the Dev.to importer as I repost all my posts on dev.to anyway. Unfortunately, the bulk import didn’t work for me so I had to import my posts one at a time.

This was handy though as you need to set the following for each post manually:

- Post slug
- Tags
- Canonical URL

Once all my posts were imported it was time to edit my Gatsby website to start pulling down the posts.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#gatsby-plugins)Gatsby plugins

If you do a search for `gatsby-source-hashnode` you will find a couple of plugins on the Gatsby website.

- [gatsby-source-hashnode](https://www.gatsbyjs.com/plugins/gatsby-source-hashnode)
- [gatsby-source-hashnode-devblog](https://www.gatsbyjs.com/plugins/gatsby-source-hashnode-devblog)

I decided to go with the first one (gatsby-source-hashnode) as it has a lot more downloads and still appears to be maintained.

However, I quickly noticed when testing out the plugin that it was only pulling down the first 6 posts from my Hashnode blog. This might be a recent change to the API which hasn’t yet been picked up by the plugins.

Luckily, the plugin is open source so I [raised a PR](https://github.com/nitzano/gatsby-source-hashnode/pull/184) for the plugin owner to review.

In the meantime, I copied my modified code to a folder in my gatsby repository called `plugins/gatsby-source-hashnode`. I then used the plugin as described in the documentation.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#graphql-queries)GraphQL queries

I am using GraphQL queries in a few places to pull down posts:

- Blog Feed
- Blog Post
- Latest Posts
- RSS Feed

For reference, this is what a couple of my queries look like for pulling from Hashnode.

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#blog-feed)Blog Feed

```
query pageQuery($skip: Int!, $limit: Int!) {
    site {
      siteMetadata {
        title
        description
      }
    }
    allHashNodePost(
      sort: { fields: [dateAdded], order: DESC }
      limit: $limit
      skip: $skip
    ) {
      edges {
        node {
          brief
          slug
          title
          coverImage {
            childImageSharp {
              gatsbyImageData(
                width: 920
                height: 483
                layout: CONSTRAINED
                transformOptions: {cropFocus: CENTER}
              )
            }
          }
        }
      }
    }
  }
```

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#blog-post)Blog Post

```
query BlogPostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        author
        siteUrl
      }
    }
    hashNodePost(slug: { eq: $slug }) {
      _id
      brief
      childMarkdownRemark {
        htmlAst
      }
      slug
      title
      dateAdded
      coverImage {
        publicURL
        childImageSharp {
          gatsbyImageData(
            width: 920
            height: 483
            layout: CONSTRAINED
            transformOptions: {cropFocus: CENTER}
          )
        }
      }
    }
  }
```

I am not yet pulling down tags or reading time from the API. That is something I will try out later.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#automation-with-github-actions)Automation with GitHub actions

I already have GitHub actions set up for my website so that any new commits to the `main` branch trigger a website build and push to S3. I [wrote a post](https://www.alexhyett.com/github-actions-deploy-to-s3) about it if you want to find out how.

However, now that I am not committing articles to that repo I needed a way to automatically trigger builds when I publish a new post on Hashnode.

Luckily, Hashnode has an option to backup your blog posts to GitHub which we can use as the trigger point.

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#step-1-add-workflow_dispatch-to-your-github-action)Step 1: Add workflow\_dispatch to your GitHub action

To be able to remotely trigger a build on GitHub you need to add `workflow_dispatch` to the `on:` section of your workflow file.

This is what the top of mine looks like:

```
name: Deploy Blog

on:
  workflow_dispatch:
  push:
    branches:
      - main
```

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#step-2-create-a-personal-access-token)Step 2: Create a personal access token

Next, we need to create a personal access token that we will use as the API Key for triggering the remote build.

You can do this in GitHub under Settings > Developer Settings > [Personal Access Tokens](https://github.com/settings/tokens)

I set my access token with the following permissions.

![GitHub Access](https://cdn.hashnode.com/res/hashnode/image/upload/v1636018806528/CHKEV-sv_.png)

You will need to set an expiry date as well and set yourself a reminder to generate a new token before it expires.

Make sure you copy the access key as you won’t get a chance again!

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#step-3-add-the-key-as-a-secret-to-your-backup-repository)Step 3: Add the key as a secret to your backup repository

To be able to use this access key we need to add it as a secret to the repository where Hashnode is backing up your posts.

On the backup repository go to Settings > Secrets and add a new repository secret called `ACCESS_TOKEN` and put in the key from the previous step.

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#step-4-add-a-workflow-file)Step 4: Add a workflow file

Next, we need to add a workflow that gets triggered every time a commit is added to this repository. In our case, this will be whenever we publish a post on Hashnode (Note: Drafts aren’t saved in GitHub).

Add the following file to your backup repository `.github/workflows/workflow.yml`

```
---
name: Trigger Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: |
          curl -X POST \
          -H "Authorization: Bearer ${{secrets.ACCESS_TOKEN}}" \
          -H "Accept: application/vnd.github.v3+json" \
          https://api.github.com/repos/GITHUB_USERNAME/WEBSITE_REPO/actions/workflows/workflow.yml/dispatches \
          -d '{"ref": "main"}'
```

Make sure you change `GITHUB_USERNAME` to match your GitHub username, `WEBSITE_REPO` to the repository with your Gatsby.js website and `workflow.yml` to match the name of your deploy workflow file.

To test, try updating one of your posts in Hashnode and you see this workflow get triggered then followed by your website workflow.