Skip to main content

Sourcing from Ghost

Ghost is an open source, professional publishing platform built on a modern Node.js technology stack — designed for teams who need power, flexibility and performance - used by Apple, NASA, Sky News, OpenAI & many more.

It comes with all the benefits of modern, centralised Headless CMS platforms, with the added benefit of being released completely for free under an MIT license, so you have total ownership and control of it without needing to depend on a third party back-end.

This guide will walk you through using Gatsby with the Ghost Content API.

Quick start

The fastest way to get started is with the official Gatsby Starter Ghost repository, which contains a light scaffolding of queries and templates to get a brand new site up and running.

Gatsby Starter Ghost

Install & setup

If you prefer to start from scratch or integrate the Ghost Content API into an existing site, you can set up the Gatsby Source Ghost plugin.

npm install --save gatsby-source-ghost


// These are working demo credentials, try them out!
module.exports = {
plugins: [
resolve: `gatsby-source-ghost`,
options: {
apiUrl: ``,
contentApiKey: `9cc5c67c358edfdd81455149d0`,

Generating pages

Once the source plugin is set up, you can use the createPages API in gatsby-node.js to create queries on your Ghost data with GraphQL. In this example, Gatsby iterates over each post returned by the Ghost API and generates a new page with that data, using the post.js template file.

There are several ways to structure queries depending on how you prefer to work, but here’s a very minimal example:

const path = require(`path`)
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const postTemplate = path.resolve(`./src/templates/post.js`)
// Query Ghost data
const result = await graphql(`
allGhostPost(sort: { order: ASC, fields: published_at }) {
edges {
node {
// Handle errors
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
if (! {
// Create pages for each Ghost post
const items =
items.forEach(({ node }) => {
node.url = `/${node.slug}/`
path: node.url,
component: path.resolve(postTemplate),
context: {
slug: node.slug,

Outputting data

Then, within the post.js template, you can determine exactly how and where you want to output data on each page. Again, you’ll use GraphQL to query individual fields, so a simple example looks something like this:

import React from "react"
import { graphql } from "gatsby"
const Post = ({ data }) => {
const post = data.ghostPost
return (
<article className="post">
{post.feature_image ? (
<img src={post.feature_image} alt={post.title} />
) : null}
<section dangerouslySetInnerHTML={{ __html: post.html }} />
export default Post
export const postQuery = graphql`
query($slug: String!) {
ghostPost(slug: { eq: $slug }) {

Wrapping up

You should have a broad understanding of how Gatsby and the Ghost Content API work together now in order to use Ghost as a headless CMS. Your writers can enjoy the slick administration experience, while your development team can keep using their ideal tooling. Everyone wins!

Here are some further resources and reading material to help you get started with some more advanced examples and use-cases:

Edit this page on GitHub