Programmatic Page Generation
Tags: gatsby
Published: 2019-08-22 15:56:07

---
title: Programmatic Page Generation
published: true
tags: gatsby,
canonical_url: https://stephencharlesweiss.com//2019-08-04/programmatic-page-generation-graphql-gatsby/
---

# <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>Programmatic Page Generation

Alright, I’ve been building to this point! Time to generate new pages for a blog programmatically using Gatsby!

Previously I wrote about configuring Gatsby’s `gatsby-source-filesystem` plugin¹ and writing GraphQL queries that take variables.² This post will combine these two lessons to generate pages to follow a simple layout for each post in my filesystem.

This post begins assuming a configured `gatsby-source-filesystem` and at the point where I’m ready to set up my `gatsby-node` file to create pages.

First, the `gatsby-node` is one of several files that Gatsby looks for in the root directory (`gatsby-config` is another as an example).

Gatsby comes with a suite of built-in plugins. To make use of any of them, you export them from the `gatsby-config` file. I’ll be using the `createPages` asynchronous operation.

For example:

```javascript
exports.createPages = async ({ actions, graphql, reporter }) => {
  // In node (which this is), graphql is a function that takes a string.
  const result = await graphql(`
    query {
      allMdx {
        nodes {
          frontmatter {
            slug
          }
        }
      }
    }
  `);
  if (result.errors) {
    reporter.panic('failed to create posts', result.errors);
  }

  const posts = result.data.allMdx.nodes;

  posts.forEach(post => {
    const path = post.frontmatter.slug;
    actions.createPage({
      path,
      component: require.resolve('./src/templates/post.js'),
      context: {
        slug: post.frontmatter.slug,
      },
    });
  });
};
```

Walking through this function:

1. I assign the value of `result` to the returned value of the GraphQL query. The returned result _is_ the slug. Notice that in `node` the GraphQL query is wrapped in `()`. 
2. 

I check for errors (`result` returns a promise with a `.error` attribute ³)

  - The Gatsby `reporter` is a built-in console log. `Panic` is an error state. 
3. If I get past the error check, then I know I have at least something returned, which means that the I can pull out our nodes. In my very simple example so far - I have two: ![](&&&SFLOCALFILEPATH&&&E40FCF47-FD5C-4F81-AF07-8255FF1B226A.png)
4. Since it’s an array, I can now loop over it using a `forEach` to generate a page using Gatsby’s built-in `actions`. Gatsby uses Redux to manage state and ships with a series of built in actions (of which `createPage` is one). ⁴

The `createPage` action API takes an object, and two optional parameters (`plugin` and `actionOptions` ) neither of which I need for this simple use case.

The object I identify has three things:

1. The path — which will be where the page I’m creating will live
2. The component — a path reference to, in this case, where I’ve saved a template for a post
3. The context — any context we will need for generating the component. This _could_ include the body and any assets for the post, however, in this example I’m putting that into the post itself and separating concerns a bit. 

At this point, I’m ready to look at the `post` file I’ve noted as the component to in the action.

For example - a simple Post layout could look like:

```javascript
import React from ‘react’;
import { graphql, Link } from ‘gatsby’;
import { MDXRenderer } from ‘gatsby-mdx’;
import Layout from ‘../components/layout’;

export const query = graphql`
  query($slug: String!) {
    mdx(frontmatter: { slug: { eq: $slug } }) {
      frontmatter {
        title
        author
      }
      code {
        body
      }
    }
  }
`;

const PostTemplate = ({ data: { mdx: post } }) => {
  const { frontmatter, code } = post;

  return (
    <Layout>
      <h1>{frontmatter.title}</h1>
      <p style={{fontSize: '0.75rem'}}>
        {`posted by ${frontmatter.author}`}
      </p>
      <MDXRenderer>{code.body}</MDXRenderer>
      <Link to=“/“>Return to home</Link>
    </Layout>
  );
};

export default PostTemplate;
```

A few notes here:The slug that’s being passed in from the `gatsby-node` configuration is the context with which I’m going to query for the data to generate the post.

I wrote my blog posts as `.mdx` files and resolve any `.mdx` or `.md` files using the `gatsby-mdx` plugin. The nice thing about doing this is that I can use the `MDXRenderer` to easily render the body of the posts.

What does all of this mean?

Any time I add a new post to my filesystem that is returned in my all MDX query in the node modules, it will get passed through to the a `createPage` action and rendered with the `MDXRenderer` in a basic format of:

1. Title
2. Author
3. Body
4. Return to home.

Pretty nifty!

- ¹ [Getting Started With Gatsby-Source-Filesystem | /\* Code Comments \*/](https://www.stephencharlesweiss.com/2019-07-20/gatsby-source-filesystem/)
- ² [How To Use Variables GraphQL Queries | /\* Code Comments \*/](https://www.stephencharlesweiss.com/2019-07-24/graphql-variable-queries/)
- ³ [Programmatically create pages from data | GatsbyJS](https://www.gatsbyjs.org/tutorial/part-seven/#creating-pages)
- ⁴ [Actions | Gatsby](https://www.gatsbyjs.org/docs/actions/)