Why and how I use Gatsby.js
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
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.
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.