Unleashing the Power of Content Sourcing in Gatsby.js

Gatsby.js has taken the web development world by storm as a blazing-fast static site generator with a rich plugin ecosystem. One of Gatsby‘s most powerful features is its flexible content sourcing capabilities. Whether your content lives in local files, a headless CMS, or even a database, Gatsby makes it easy to pull that data into your components and pages.

In this comprehensive guide, we‘ll dive deep into sourcing content with Gatsby.js. You‘ll learn multiple techniques for sourcing various types of content and integrating it into your Gatsby site. By the end, you‘ll be a master at fueling your sites with content from any source imaginable. Let‘s jump in!

Sourcing Content from the Filesystem

One of the simplest ways to source content with Gatsby is to load it directly from your project‘s filesystem. This is a great approach for smaller sites where you want to maintain full control over your content in local files. The gatsby-source-filesystem plugin makes this process a breeze.

First, install the plugin:

npm install gatsby-source-filesystem

Then add it to your gatsby-config.js:

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `content`,
        path: `${__dirname}/content`,
      },
    },
  ],
}

Here we‘re telling gatsby-source-filesystem to source files from the content directory in our project. The name option allows us to filter the sourced files by the filesystem they came from.

Querying Filesystem Images

Let‘s say we have an image file at content/images/avatar.png that we want to display on our site. We can query it using GraphQL like this:

query {
  file(relativePath: {eq: "images/avatar.png"}) {
    childImageSharp {
      fixed(width: 200, height: 200) {
        ...GatsbyImageSharpFixed
      }
    }
  }
}

This queries for a file with the relative path images/avatar.png and accesses its childImageSharp field to get a fixed-size, optimized version of the image to display. The ...GatsbyImageSharpFixed fragment includes all the necessary fields for displaying a fixed image.

You can then use the queried data in a component:

const Avatar = ({ data }) => (
  <Img fixed={data.file.childImageSharp.fixed} alt="Avatar" />
);

export default Avatar;

export const query = graphql`
  query {
    file(relativePath: {eq: "images/avatar.png"}) {
      childImageSharp {
        fixed(width: 200, height: 200) {
          ...GatsbyImageSharpFixed
        }
      }
    }
  }
`;

Transforming Markdown Content

In addition to images, a common use case is sourcing content from Markdown files. Gatsby has a powerful Markdown processing plugin called gatsby-transformer-remark that converts Markdown files to HTML and provides additional features like syntax highlighting.

Install the transformer along with gatsby-source-filesystem:

npm install gatsby-transformer-remark gatsby-source-filesystem

Configure the plugins in gatsby-config.js:

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `content`,
        path: `${__dirname}/content`,
      },
    },
    `gatsby-transformer-remark`,
  ],
}

Now any Markdown files in the content directory will be processed and available to query via GraphQL. For example, let‘s say we have a Markdown file at content/posts/hello-world.md:

---
title: Hello World
date: 2020-01-01
---

This is my first blog post!

## Nice to meet you

I hope you‘ll enjoy my posts.

We can query the transformed HTML as well as any frontmatter fields like this:

query {
  allMarkdownRemark {
    nodes {
      html
      frontmatter {
        title
        date(formatString: "MMMM D, YYYY")
      }
    }
  }
}

The frontmatter fields become available under the frontmatter field, while the converted HTML is available under the html field. This structured data can then be used to programmatically create pages:

// gatsby-node.js
const path = require(`path`);

exports.createPages = async ({ actions, graphql }) => {
  const { createPage } = actions;

  const result = await graphql(`
    query {
      allMarkdownRemark {
        nodes {
          frontmatter {
            slug
          }
        }
      }
    }
  `);

  result.data.allMarkdownRemark.nodes.forEach(node => {
    createPage({
      path: node.frontmatter.slug,
      component: path.resolve(`./src/templates/post.js`),
      context: {
        slug: node.frontmatter.slug,
      },
    });
  });
};

This queries all the Markdown nodes for their slugs and programmatically creates a page for each one using a post template component.

Sourcing from Headless CMSs

While sourcing from local files works great for simple sites, many larger projects opt to use a headless CMS to manage their content. A headless CMS provides a user-friendly interface for content creators while exposing the content via an API for developers to consume.

Gatsby has source plugins for most of the popular CMSs like Contentful, Drupal, Sanity, and more. As an example, let‘s see how to source content from Contentful.

Start by installing the gatsby-source-contentful plugin:

npm install gatsby-source-contentful

In your gatsby-config.js, configure the plugin with your Contentful space ID and access token:

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-contentful`,
      options: {
        spaceId: `your_space_id_here`,
        accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
      },
    },
  ],
}

It‘s a good practice to use environment variables for sensitive information like access tokens. You can set these variables locally in a .env file or configure them in your deployment environment.

With the plugin configured, you can query your Contentful data using GraphQL. The exact query will depend on your content model, but here‘s an example for a generic "post" content type:

query {
  allContentfulPost(sort: { fields: publishDate, order: DESC }) {
    nodes {
      title
      slug
      publishDate(formatString: "MMMM D, YYYY")
      content {
        childMarkdownRemark {
          html
        }
      }
    }
  }
}

This query retrieves all posts sorted by publish date. The title, slug, and publishDate fields are simple text and date fields, but the content field is a rich text field that is transformed to Markdown using the childMarkdownRemark field.

You can then use this data to programmatically create pages or display it in components just like with the filesystem data.

Avoiding Sourcing Conflicts

When sourcing content from multiple locations, it‘s important to be specific in your queries to avoid conflicts. For example, if you‘re sourcing Markdown content from both your filesystem and a CMS, you might need to update any allMarkdownRemark queries to filter by a specific source:

query {
  allMarkdownRemark(filter: {
    fileAbsolutePath: {regex: "/content/"}
  }) {
    ...
  }
}

This query only returns Markdown nodes sourced from the content directory in your filesystem, ignoring any Markdown from the CMS.

Recap & Further Reading

In this guide, we‘ve explored several powerful techniques for sourcing content with Gatsby.js. Whether your content lives in local files or a headless CMS, Gatsby provides the tools to easily pull that data into your components and pages.

Some key takeaways:

  • Use gatsby-source-filesystem to source content from local files
  • Transform and query Markdown files using gatsby-transformer-remark
  • Source content from a headless CMS like Contentful using source plugins
  • Filter queries by source to avoid conflicts when using multiple content sources

This just scratches the surface of what‘s possible with Gatsby‘s content sourcing capabilities. To dive deeper, check out the Gatsby docs on sourcing content and working with images. You can also explore the wide world of Gatsby source plugins to find plugins for your favorite CMSs and data sources.

Happy Gatsby-ing! May your content be plentiful and your builds be fast.

Similar Posts