Why and how I use Gatsby.js

kurtmcintire

Kurt McIntire

04.15.2020

I use Gatsby.js for my personal blog and Gear List. Both sites are primarily static, blog-like content. Gatsby helped me get these sites up and running quickly. After a year of growing and customizing these sites, I’m pleased to report that Gatsby scaled with me well.

In this post, I’ll explain:

  • What is Gatsby?
  • Why Gatsby?
  • What Gatsby is not
  • Getting started with Gatsby
  • How I structure my Gatsby sites
  • How Gatsby works
  • Loading static content with JSON
  • Loading dynamic content
Gear List

I use Gatsby for my blog and side projects.

What is Gatsby?

Gatsby is a framework for building static-content websites with React.js. Think blogs, news sites, and marketing sites. For these types of websites, most of the content is authored by site owners, versus generated by users. Gatsby is optimized for building this type of static site quickly and with sensible defaults.

Why Gatsby?

As a developer, Gatsby provides solid documentation, a vibrant developer community, and a great starter project in which to fork and build on.

As a business owner, Gatsby sites load quickly for your customers and are easily crawled by search engines. This means that performing well from a SEO standpoint is easier with Gatsby sites than many popular site building frameworks today.

What Gatsby is not

Gatsby is not a WYSIWYG site builder like Squarespace or Weebly. This means that Gatsby does not provide a site builder tool that lets you drag and drop website building blocks together. Gatsby sites are built using React.js code. If you are a non-technical person, I recommend using a different tool to build your sites.

Gatsby is not a CMS, meaning it does not provide an admin panel for authoring blog posts and pages. Out of the box, authoring content with Gatsby happens by editing code files. If you’ve built a website with WordPress, you’re accustomed to creating pages, templates, and blog posts using the admin panel at <yoursite>.com/admin. Despite not being a CMS, Gatsby is compatible with a number of CMS providers like Contentful.

Getting started with Gatsby

Gatsby provides a gatsby-starter-blog project as a starting point for new developers. This Javascript project provides basic configuration and file-folder structures. Running your new Gatsby site locally takes a few commands.

npm install -g gatsby-cli
gatsby new <your-site> https://github.com/gatsbyjs/gatsby-starter-blog
cd <your-site>
gatsby develop

With this, visit http://localhost:8000 to see your site. It should look something like this demo, which is deployed here.

If you want a no-frills blog, you won't need to do much customization beyond this. However, if you want to customize your blog, or begin building pages for a marketing site, you'll need to know more about the file and folder structure that make up Gatsby projects.

How my sites are structured

Gatsby projects are structured to separate content from code. At the root of my sites, you'll find two key folders. src, and content. Inside of content are two folders called blog and pages. Inside of blog and pages are markdown (.md) files. Markdown files hold the text of my blog posts and marketing pages, but don't specify fonts, colors, navigation bars, tables, and other building blocks that make up websites.

content/
  blog/
    blog01
      index.md
    blog02
      index.md
  pages/
    contact/
      index.md
    books/
      index.md
    skillset/
      index.md
src/
  components/
  constants/
  lib/
  pages/
    contact.js
    books.js
    skillset.js
  templates/
    blog-post.js
  styles/

Code, like how a button should look, or how a navigation bar should behave, or how a page is structured goes in the src folder. Some common subfolders of my src folder are components, constants, lib, pages, styles, and templates. Notice that my src folder has a pages folder, as does my content folder. This illustrates the separation of code and content. In content/pages, I have markdown files that hold the text and images that make up my non-blog site pages. In src/pages I have Javascript files that specify how these pages look and behave.

In content/blog, I have my blog posts. And similarly, in src/templates/ I have a corresponding Javascript file called blog-post.js. blog-post.js lives in my src/templates subdirectory instead of src/pages because there are many blog posts. Unlike my site's /books or /skillset pages, blog posts all follow the same layout and structure. So, I put Javascript files that can render many markdown files in the src/templates folder and Javascript files that render one markdown file in src/pages.

How Gatsby works

Note that to launch the gatsby-starter-blog, I had you run the gatsby develop command. This command compiles Gatsby projects, combining content and code into a single file that is served to the user when they request a URL like /blog or /about. Gatsby creates a website page for each Javascript page and markdown page. As a developer bonus, once gatsby develop is run, Gatsby detects content and code changes in your project, automatically updating what you see at localhost:8000.

So, let's look at the Books page of this site. If you visit kurtmcintire.com/books, you'll see a list of books I've read. The /books page consists of one markdown (.md) file and one Javascript (.js) template.

In my books markdown file is the raw text, listing out all of my books.

---
type: books
title: Books
subtitle: This is a list of some of the books I've read. I generally enjoy non-fiction focusing on business, software, and fitness.
---

### 2020

- [Can't Hurt Me: Master Your Mind and Defy the Odds](https://amzn.to/2R6iW1g), David Goggins
- [Sapiens](https://amzn.to/2Uwhrf1), Yuval Noah Harari
- [The Way I Heard It](https://amzn.to/3bLBegx), Mike Rowe
- [The Sun Also Rises](https://amzn.to/2UnEoRw), Ernest Hemingway
- [Training for the Uphill Athlete: A Manual for Mountain Runners and Ski Mountaineers](https://amzn.to/39oaCk4), Steve House, Scott Johnston, Kilian Jornet

In my books Javascript file is a React.js component which specifies how the page is laid out and will behave. If you're familiar with React.js, this should look standard-issue. However, note the booksQuery at the bottom of the file.

const BooksPage = props => {
  const htmlAst = props.data.allMarkdownRemark.edges[0].node.htmlAst
  const frontmatter = props.data.allMarkdownRemark.edges[0].node.frontmatter

  return (
    <Layout override="marginStandard">
      <SEO title={frontmatter.title} />
      <div className="marginFocus">
        <Title>{frontmatter.title}</Title>
        <p>{frontmatter.subtitle}</p>
        <div style={styles.bodyText}>{renderAst(htmlAst)}</div>
      </div>
    </Layout>
  )
}

export default BooksPage

export const booksQuery = graphql`
  query booksQuery {
    allMarkdownRemark(
      sort: { order: DESC, fields: frontmatter___date }
      filter: { frontmatter: { type: { eq: "books" } } }
    ) {
      edges {
        node {
          frontmatter {
            type
            title
            subtitle
          }
          fields {
            slug
          }
          htmlAst
        }
      }
    }
  }
`

Gatsby uses GraphQL to expose static content to code files. Notice that the booksQuery uses GraphQL query syntax to fetch all markdown of type books. From there, the query syntax specifies the type of information that it wants within the books markdown. In this case, it queries for the main content htmlAst, and the frontmatter. The frontmatter is the markdown's metadata listed at the top of the books markdown file, as shown below. The GraphQL query for frontmatter requests type, title, and subtitle, which are the exact values at the top of the books markdown file.

---
type: books
title: Books
subtitle: This is a list of some of the books I've read. I generally enjoy non-fiction focusing on business, software, and fitness.
---

Then, the htmlAst is the content below the frontmatter. It's basically the raw text making up my books list.

Loading static content with JSON

Gatsby's combination of static markdown and React.js to build websites covers most of my use cases. However, recently on Gear List, I wanted to load a list of athletes and metadata about these athletes. Some of the data on this page lived in markdown files, like article count.

Gear List Athletes

Gatsby can load non-markdown static content, like JSON files.

However, some of it, like Instagram profile pictures, did not. I created a JSON file that held a list of athletes and their metadata.

[
  {
    "name": "Johnny Luna-lima",
    "image": "https://scontent-atl3-1.cdninstagram.com/v/t51.2885-19/s320x320/34465149_208846659725678_2433838708286291968_n.jpg?_nc_ht=scontent-atl3-1.cdninstagram.com&_nc_ohc=--T2ZsmGkL4AX-zHEKa&oh=a6beb460d9ba324b90914df5453bdfc9&oe=5EB45C84",
    "id": "johnny-luna-lima"
  },
  {
    "name": "Tyler Veerman",
    "image": "https://scontent-atl3-1.cdninstagram.com/v/t51.2885-19/s320x320/82586191_858150587971873_2002629265987731456_n.jpg?_nc_ht=scontent-atl3-1.cdninstagram.com&_nc_ohc=-fiM2nb5HaUAX__Xzb1&oh=8d90d53bcbe89ac05df9f215fb1913a1&oe=5EB463AF",
    "id": "tyler-veerman"
  },
]

My /athletes page loads this JSON file and combines it with the GraphQL query specified at the bottom of athletes.js, shown below.

import AthletesJson from "../../content/athletes.json"

const AthletesPage = props => {
  const data = props.data.allMarkdownRemark.group
  const athletes = data.sort((a, b) => b.totalCount - a.totalCount)

  return (
    <TagsList
      title={Strings.Athletes.Title}
      tags={athletes}
      tagsJson={AthletesJson}
    />
  )
}

export default AthletesPage

export const pageQuery = graphql`
  query {
    allMarkdownRemark(limit: 2000) {
      group(field: frontmatter___athletes) {
        fieldValue
        totalCount
      }
    }
  }
`

Loading dynamic content

Just because Gatsby is optimized for static content, it doesn't mean that you cannot utilize dynamic content on your site. Since the code part of your Gatsby project is just React.js Javascript, you can perform network requests. Inside of your pages, you can GET data from REST APIs, open a websocket, or post data to a server. React's useEffect hook is a clean way to perform a fetch (or adding on componentDidMount). I haven't yet had a good reason to load dynamic content for Gear List or this blog, but it's great to know that Gatsby doesn't paint me into a corner to only work with static content.

  const [starsCount, setStarsCount] = useState(0)
  useEffect(() => {
    fetch(`https://api.github.com/repos/gatsbyjs/gatsby`)
      .then(response => response.json())
      .then(resultData => {
        setStarsCount(resultData.stargazers_count)
      }) // set data for the number of stars
  }, [])

Conclusion

Gatsby is a powerful developer-friendly way to build websites. If you're building a marketing site, blog, or news site primarily powered by static content, I recommend Gatsby. I've found it to be invaluable as I built out my personal blog and side projects.