Skip to content

Tips & Tricks for Gatsby


Created: Mar 02, 2019 – Last Updated: Nov 18, 2021

React

For some time now I’ve been trying to publish quick tips about Gatsby on Twitter, because the community loves such short, useful tips. Accordingly, I had already created a Twitter moment (opens in a new tab) back then – but why only content from me? On January 6th of this year I also called the community to share their quick tips (with great success). As promised, this blogpost is supposed to be a collection of these (and other) tips. You can also tag me on Twitter (opens in a new tab) if you want to add your tip to the moment!

Some tips are also accompanied by CodeSandbox (opens in a new tab) examples.

#Date of last Build

Gives you the date for when you last used gatsby build. In the case of e.g. Netlify that would be the last time you deployed your site (hence buildTime). Please use this query sparingly (e.g. not in your footer component that you share with every page) as otherwise on every build the queries would be invalidated (since the time changed) and you’d unnecessarily rebuild all pages.

CodeSandbox (opens in a new tab)

jsx
import * as React from "react"
import { graphql } from "gatsby"
const IndexPage = ({ data }) => {
return (
<main>
<p>This site was last built on:</p>
<p>{data.site.buildTime}</p>
</main>
)
}
export default IndexPage
export const query = graphql`
query {
site {
buildTime(formatString: "DD/MM/YYYY")
}
}
`

#Date of last modification

For open source docs it’s good to know when a document was last modified. You can get that information via the parent if you use local files like Markdown, MDX, YAML etc. Use the ___graphql endpoint to explore that information on your own project.

CodeSandbox (opens in a new tab)

graphql
query {
allMdx {
nodes {
parent {
... on File {
modifiedTime(formatString: "MM/DD/YYYY")
}
}
}
}
}

#Same Source, different Queries

When you define two (or more) gatsby-source-filesystem entries in your config you can filter your GraphQL queries to only get the result of one source.

CodeSandbox (opens in a new tab)

gatsby-config.js
js
module.exports = {
plugins: [
{
resolve: "gatsby-source-filesystem",
options: {
name: "assets",
path: `${__dirname}/src/assets`,
},
},
{
resolve: "gatsby-source-filesystem",
options: {
name: "logos",
path: `${__dirname}/src/logos`,
},
},
"gatsby-transformer-sharp",
"gatsby-plugin-sharp",
],
}

Now place one image file in the src/logos folder and two or more image files in the src/assets folder. This should show the difference between the file and allFile query (of course you can put any number of files into one folder). You can address both folders individually, as shown in the following example:

js
import * as React from "react"
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
const IndexPage = ({ data }) => {
return (
<main>
<p>First image (logo):</p>
<GatsbyImage image={getImage(data.logo)} />
<p>Assets images (two):</p>
<div style={{ display: "flex", flexWrap: "wrap" }}>
{data.assets.nodes.map((img) => (
<GatsbyImage image={getImage(img.childImageSharp)} />
))}
</div>
</main>
)
}
export default IndexPage
export const query = graphql`
query {
logo: file(sourceInstanceName: { eq: "logos" }) {
childImageSharp {
gatsbyImageData(width: 200, quality: 100)
}
}
assets: allFile(filter: { sourceInstanceName: { eq: "assets" } }) {
nodes {
childImageSharp {
gatsbyImageData(width: 200, quality: 100)
}
}
}
}
`

#Gatsby’s reporter API

You can not only use async/await in gatsby-node.js but also use Gatsby’s reporter API. Use this to throw errors. You should use panicOnBuild to only stop the process on gatsby build (so that you can debug it with GraphiQL).

gatsby-node.js
js
const yourTemplate = require.resolve("./src/templates/yourTemplate.js")
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const result = await graphql(`
{
...your
GraphQL
query
}
`)
if (result.errors) {
reporter.panicOnBuild("Error while running GraphQL query.")
return
}
result.data.yourNode.nodes.forEach((node) => {
// createPage function
})
}

Most of the time you want to show a previous/next post under your blog post to keep the visitor reading. For that you can use pageContext.

CodeSandbox (opens in a new tab)

gatsby-node.js
js
const bookTemplate = require.resolve("./src/templates/book.js")
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const result = await graphql(
graphql(`
{
allBooksYaml(sort: { fields: [title], order: ASC }) {
nodes {
slug
title
}
}
}
`)
)
if (result.errors) {
reporter.panicOnBuild("Error while running GraphQL query.")
return
}
const books = result.data.allBooksYaml.nodes
books.forEach((node, index) => {
// Set the prev/next variable for every node so
// that you can directly access slug & title
const prev = index === 0 ? null : books[index - 1]
const next = index === books.length - 1 ? null : books[index + 1]
createPage({
path: node.slug,
component: bookTemplate,
context: {
slug: node.slug,
prev,
next,
},
})
})
}
src/templates/book.js
js
import * as React from "react"
import { graphql, Link } from "gatsby"
import Layout from "../components/layout"
const BookTemplate = ({ data: { booksYaml }, pageContext: { prev, next } }) => {
return (
<Layout>
<h2>{booksYaml.title}</h2>
<div>
{prev && (
<div>
<span>Previous</span>
<Link to={prev.slug}>{prev.title}</Link>
</div>
)}
{next && (
<div>
<span>Next</span>
<Link to={next.slug}>{next.title}</Link>
</div>
)}
</div>
</Layout>
)
}
export default BookTemplate
export const pageQuery = graphql`
query BookBySlug($slug: String!) {
booksYaml(slug: { eq: $slug }) {
title
content
}
}
`

In contrast to the previous tip you can also show two (or more) random posts by changing gatsby-node.js.

CodeSandbox (opens in a new tab)

gatsby-node.js
js
const _ = require("lodash")
const prevNext = (list, item) => {
// Create a random selection of other posts (excluding the current post)
const filterUnique = _.filter(list, (input) => input.slug !== item.slug)
const sample = _.sampleSize(filterUnique, 2)
return {
prev: sample[0],
next: sample[1],
}
}
const bookTemplate = require.resolve("./src/templates/book.js")
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const result = await graphql(
graphql(`
{
allBooksYaml(sort: { fields: [title], order: ASC }) {
nodes {
slug
title
}
}
}
`)
)
if (result.errors) {
reporter.panicOnBuild("Error while running GraphQL query.")
return
}
const books = result.data.allBooksYaml.nodes
books.forEach((node) => {
const { prev, next } = prevNext(books, node)
createPage({
path: node.slug,
component: bookTemplate,
context: {
slug: node.slug,
prev,
next,
},
})
})
}

#Download Images from a CDN

If your images are hosted on a CDN and you want to use gatsby-plugin-image, you can download them using the createRemoteFileNode helper. Then add the image to the respective node.

This example assumes that you have Gatsby set up with Markdown and want to use the following frontmatter:

md
---
title: My first blog post!
featuredImgUrl: https://images.unsplash.com/photo-1560237731-890b122a9b6c
featuredImgAlt: Mountains with a starry sky
---
gatsby-node.js
js
const { createRemoteFileNode } = require("gatsby-source-filesystem")
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
createTypes(`
type MarkdownRemark implements Node {
frontmatter: Frontmatter
featuredImg: File @link(from: "fields.localFile")
}
type Frontmatter {
title: String!
featuredImgUrl: String
featuredImgAlt: String
}
`)
}
exports.onCreateNode = async ({
node,
actions: { createNode, createNodeField },
store,
cache,
createNodeId,
}) => {
// For all MarkdownRemark nodes that have a featured image url, call createRemoteFileNode
if (
node.internal.type === "MarkdownRemark" &&
node.frontmatter.featuredImgUrl !== null
) {
const fileNode = await createRemoteFileNode({
url: node.frontmatter.featuredImgUrl, // string that points to the URL of the image
parentNodeId: node.id, // id of the parent node of the fileNode you are going to create
createNode, // helper function in gatsby-node to generate the node
createNodeId, // helper function in gatsby-node to generate the node id
cache, // Gatsby's cache
store, // Gatsby's Redux store
})
// if the file was created, extend the node with "localFile"
if (fileNode) {
createNodeField({ node, name: "localFile", value: fileNode.id })
}
}
}

#Analyse your Bundle Sizes

Don’t know exactly why some of your pages load slowly? No problem, you can use gatsby-plugin-webpack-bundle-analyser-v2 (opens in a new tab) to find the culprits.

After installation and setup you’ll see a visual representation of all your bundles.

sh
npm install gatsby-plugin-webpack-bundle-analyser-v2 -D

And in your gatsby-config.js:

gatsby-config.js
js
module.exports = {
plugins: ["gatsby-plugin-webpack-bundle-analyser-v2"],
}

Once you run a gatsby build at the end of a build (locally) the browser will open with the bundle analyser.

#More tips!

You can read more posts about Gatsby in my Digital Garden or in the React writing category. Some highlights:

#Your tips?

Do you have any tips that I should add to this list? Let me know on Twitter at @lekoarts_de (opens in a new tab) and I’ll add them!