Cover image for How to Turn an Existing Gatsby Site Into a Theme

How to Turn an Existing Gatsby Site Into a Theme

laurieontech profile image Laurie Originally published at tenmilesquare.com ・5 min read

If you haven't caught the live stream where we did this, check it out here! While this post is informative and will cover most of what we worked on, I genuinely cannot reproduce that level of comedy and banter. @jlengstorf is a blast.

Also, full credit to @likeomgitsfeday whose site was the original inspiration (and architecture) for mine!

With that as a primer, let's dig into the code.

Project Setup

My project exists in a slightly cluttered personal directory. So to start things out, we're going to move it into a new folder. The incredibly named, site-and-stuff. This isn't strictly necessary, it just helps for organizational purposes.

From there, it's time to setup the theme project and associated yarn workspace.

Initialize Theme

Inside site-and-stuff I'll make a directory called gatsby-theme-speaking-yaml. That means that site-and-stuff currently contains that theme project and my original site project, gatsby-laurieontech.

Now we want to initialize my theme project. To do this, we'll run the following command inside gatsby-theme-speaking-yaml.

yarn init -y

This creates a package.json with some existing information. However, we also want to add a few additional items, author and keywords. The whole thing ends up looking like this.

  "name": "gatsby-theme-speaking-yaml",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "author": "Laurie on tech",
  "keywords": ["gatsby", "gatsby-plugin", "gatsby-theme"]

Note that our main points to index.js. This file doesn't currently exist so we need to create it. It doesn't need any content at the moment, so we'll just put in a comment for now and that will be sufficient.

Setup Workspace

We also need to create a package.json in our root directory, site-and-stuff. In this case we'll just create the file and add some information manually. It ends up looking like this.

  "private": true,
  "workspaces": ["gatsby-laurieontech", "gatsby-theme-speaking-yaml"]

To test out that this worked, you can run the following command.

yarn workspaces info

Install Theme Into Site

Next, we'll add our theme to our site. But we have to do one quick thing first.

Part of the reference data for my site is in the key-value pairs in package.json for the gatsby-laurieontech project. I may or may not have forgotten to change this from the default, but now it's laurieontech. This snippet is truncated for readability.

  "name": "laurieontech",
  "description": "Laurie never changed the starter description, oops",
  "version": "1.0.0",
  "author": "Laurie Barth"

This is important because it's how we're referencing the site project in the yarn workspace. So now we can add the theme to the site.

yarn workspace laurieontech add gatsby-theme-speaking-yaml@*

It's written like this, with the @*, because the theme is unpublished.

To test out that this works, you can run this command again. You should see the theme listed inside the site information.

yarn workspaces info

We also want to add the theme as a plugin to the gatsby-config.js file for our site, gatsby-laurieontech.

module.exports = {
  plugins: [
    // other stuff goes here

Install Dependencies into Theme

Now we want to start developing the theme itself. The first thing to do is figure out what dependencies the theme has. In our case, we're querying yaml and processing images. So we'll install those dependencies.

yarn workspace gatsby-theme-speaking-yaml add gatsby-source-filesystem gatsby-image gatsby-plugin-sharp gatsby-transformer-yaml gatsby-transformer-sharp

Next, we want to create a gatsby-config.js file inside our theme. This is where we'll add the plugins that we just installed.

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

Note that gatsby-image needed to be installed but not included, it's a utility

Create Theme

Now it's time to actually create our theme! Since we're building our theme off of an existing site, we can pull whatever code we want out of my site and place it into the theme project.

In this case, that's a section inside my speaking.js page. So we'll create src/component/speaking.js and move the relevant JSX over.

The existing code uses a page query and the theme is treating this section as a component, so it needs to use a static query instead. We'll make the change like so.

import React from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import Img from 'gatsby-image'
import Event from './event'

const SpeakingSection = () => {
  const data = useStaticQuery(graphql`
      allSpeakingYaml(sort: { fields: [index], order: DESC }) {
        edges {
          node {
            image {
              childImageSharp {
                fluid {
            talks {
  return (
    <section id="speaking" className="wrapper style4 container">
      <div className="container">
        <div className="wrapper" id="speakwrap">
          {data.allSpeakingYaml.edges.map(({ node }) => (
            <Event event={node} />

export default SpeakingSection

Make sure data is usable

The code that is now being pulled from my theme is using data that lives inside my original project, NOT inside the theme. So I assumed that needed to move over to, but it actually doesn't!

This is where Laurie realizes that the theme doesn't need to hold the data, and when everything is compiled together it will be able to see all my yaml stuff!

However, in order to make sure that it works we need to check the gatsby-config.js for the theme to make sure it's using the correct relative path. In my case, that means minor changes to the gatsby-source-filesystem plugin configuration.

module.exports = {
  plugins: [
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `src/data/`,

Export theme component

The guts of our theme exist in src/components/speaking.js but our package.json is referencing an index.js file with only a comment in it. So we need to make sure that file is exporting our theme content.

export { default as SpeakingEvents } from './src/components/speaking'

As it turns out, we can import and export at the same time! I really should add this trick to this post.

Use theme!

Now we can use our theme as if it were just another component in our Gatsby site.

In this case, that means changing my site's speaking page and importing the component from my theme to replace existing code. Note that the import is absolute because it's equivalent to pulling in an export from another project!

import React from 'react'
import Layout from '../components/layout'
import Hero from '../components/Hero'
import { SpeakingEvents } from 'gatsby-theme-speaking-yaml'

const SpeakingPage = ({ data }) => {
  return (
      <Hero /> // this is a local component! I can use all this interchangeably
      <SpeakingEvents />

export default SpeakingPage

Run Your Site with the Theme!

Now it's time to run our project with our theme.

Remember, that instead of the site's directory name, we're actually using the name we specified in the package.json, like so.

yarn workspace laurieontech develop

And that's it! Now we can add to the theme, publish it, whatever we want.

Other Stuff we Discussed

This was quite the live stream, so naturally other things came up. Important topics such as:

  • Jason's relative height to other Gatsby employees

  • My terribleness with time zones

  • Terminal...and commands Laurie almost bricked her computer with

Oh, you meant related to our actual goal?

We did some refactoring of my app, talked about gatsby-image and a handful of other things.

At some point, I will write a post on a full refactor of my site.

But until then, I can't wait to see you all make the work you've done on your personal sites available as a theme for others to leverage.

We stand on the shoulders of the work that came before us!

Posted on by:

laurieontech profile



Software dev at Gatsby | DC techie | Conference speaker | egghead Instructor | TC39 Educators Committee | Girls Who Code Facilitator | Board game geek | @laurieontech on twitter


markdown guide