[Pre-Stable Release] Getting Started with Our First Gatsby Theme
Tags: gatsby, beginners
Published: 2019-05-11 13:19:45

---
title: [Pre-Stable Release] Getting Started with Our First Gatsby Theme
published: true
description: Create a simple Gatsby theme and use it locally
tags: gatsby, gatsbyjs, beginners
series: Learning Gatsby Themes
---

> ⚠️ **UPDATE 7/7/2019:** This post was written _before_ themes was stable. Some API and code in this post might not be accurate now. Proceed with caution. ⚠️

---

🧐 _To learn more about Gatsby themes, check out my [first](https://dev.to/ekafyi/learning-gatsby-themes-introduction-1gje) and [second](https://dev.to/ekafyi/using-gatsby-themes-in-a-non-theme-starter-54c7) posts in this series._

A Gatsby **theme** is a _reusable block of a Gatsby site_ that can be _shared, extended, and customized_ ([source](https://youtu.be/SV2zu9FvUTw?t=406)). It enables us to separate functionalities of our site to share, reuse, and modify in multiple sites in a modular way.

In this post, we get started with theming by _building a basic, bare-bones theme_ called `gatsby-theme-hello-world`. We are creating this _locally_, meaning the files are on our local machine and we are not going to publish the theme yet. To check if the theme is usable, we are also going to create a new blank site, add the theme, and add content from our site.

This is mostly based on the first 24 minutes of [this video by John Otander and Jason Lengstorf](https://www.youtube.com/watch?v=PS2784YfPpw) with minor modifications.

Let's go!

![the band Ramones on stage with text Hey Ho, Let's Go!](https://media.giphy.com/media/5HMukcn0XDp5K/giphy-downsized.gif)

**Table of Contents**
1. Create folders
2. Create `package.json` in ROOT, THEME, and SITE
3. Add devDependencies and peerDependencies to THEME
4. Add dependencies to THEME
5. Create index page and post in THEME
6. Add dependencies (including the theme) to SITE
7. Create a post in SITE
8. Add a ghost (optional)

> ⚠️ Gatsby Themes are currently experimental. Theme API might change in the future. ⚠️

---


### 1. Create our folders

We are creating our project folder that contains two folders for the theme and the site respectively. Therefore, we are talking about _three_ locations:
- project (workspace) ROOT — I’m calling it `eka-site-with-theme`, feel free to use any other name
- THEME — `eka-site-with-theme/gatsby-theme-hello-world`
- SITE — `eka-site-with-theme/example-site`

```sh
# create and go to our project folder
mkdir eka-site-with-theme
cd eka-site-with-theme

# make our theme and site folders
mkdir gatsby-theme-hello-world example-site 
```
If you are comparing with [this video](https://www.youtube.com/watch?v=PS2784YfPpw), the project root is `gatsby-themes`, the theme folder is `gatsby-themes/packages/gatsby-theme-livestream`, and the site folder is `gatsby-themes/site`. You can arrange and name your folders any way you want. Just make sure to refer to the subfolders correctly in the next step!

**Note:** You don’t have to create the SITE part from scratch. Alternatively, you can [use `gatsby new` command](https://www.gatsbyjs.org/tutorial/part-zero/#create-a-gatsby-site) as usual , or use the theme with your _existing_ Gatsby site. To read more about the latter, see my post below.

{% link https://dev.to/ekafyi/using-gatsby-themes-in-a-non-theme-starter-54c7 %}

### 2. Create `package.json`

We are going to create `package.json` by running `yarn init` in _all three_ of our folders. You may fill out or skip most of the defaults, but make sure you fill out the _required_ content below.

#### 2a) ROOT

```js
// eka-site-with-theme/package.json
{
  "name": "eka-site-with-theme",
  "private": true,
  "workspaces": [
    "example-site",
    "gatsby-theme-hello-world",
  ]
}
```

As you can see, we add our _site_ and _theme_ folders in the `workspaces` array. This enables us to use themes—just the one theme, in this case—locally. Read [this post about yarn workspaces](https://github.com/gatsbyjs/gatsby/blob/beacac6215e7a527a937a121a482f0b60bd69126/docs/blog/2019-04-01-setting-up-yarn-workspaces-for-theme-development/index.md) if you’d like to know more.

The `workspaces` field accepts wildcards. If you have multiple local themes, for instance, you can put them in a folder called `packages` and add `"packages/*"` in the array instead of listing the theme folders one by one.

#### 2b) SITE (`example-site`)

```js
// eka-site-with-theme/example-site/package.json
{
  "name": "example-site",
  "version": "1.0.0",
  "private": "true"
}
```

This folder is not meant to be published, so we can set `private` to `true` and omit the entry point (`main`).

#### 2c) THEME (`gatsby-theme-hello-world`)

```js
// eka-site-with-theme/gatsby-theme-hello-world/package.json
{
  "name": "gatsby-theme-hello-world",
  "version": "1.0.0",
  "license": "MIT",
  "main": "index.js"
}
```

We have to provide an entry point (`main`) in our theme package for when Gatsby/Node attempts to resolve the package. Don’t forget to create an empty `index.js` in this folder; otherwise we would not be able to use this theme from our site later. Omitting `license` will not cause error but will throw a warning.

Now we’ve got all three package files created, go back to the root folder and run `yarn workspaces info`. Your command line should print something like this:

```sh
# eka-site-with-theme/gatsby-theme-hello-world
**yarn workspaces v1.15.2**
{
  "example-site": {
    "location": "example-site",
    "workspaceDependencies": [
      "gatsby-theme-hello-world"
    ],
    "mismatchedWorkspaceDependencies": []
  },
  "gatsby-theme-hello-world": {
    "location": "gatsby-theme-hello-world",
    "workspaceDependencies": [],
    "mismatchedWorkspaceDependencies": []
  }
}
```

In steps 3 to 5 we are going to work in the _theme_ folder, and in steps 6 and 7 we are going to work in the _site_ folder.

### 3. Install `devDependencies` and `peerDependencies` in THEME

We are installing the following packages as both `devDependencies` and `peerDependencies`:
- gatsby
- react
- react-dom

```sh
# eka-site-with-theme/gatsby-theme-hello-world
yarn add gatsby react react-dom -D -P
```

[`devDependencies`](https://yarnpkg.com/en/docs/dependency-types#toc-devdependencies) are dependencies you need for _developing_ (creating) the theme, while [`peerDependencies`](https://yarnpkg.com/en/docs/dependency-types#toc-peerdependencies) are for ensuring the same copy of these dependencies is used when our theme is installed by users.

### 4. Add dependencies to THEME

We are adding the following dependencies:
- gatsby-plugin-page-creator
- gatsby-mdx, @mdx-js/mdx, @mdx-js/tag, @mdx-js/react

#### 4a) `gatsby-plugin-page-creator`

By default, Gatsby creates pages from components in the `src/pages` folder. It’s fine for non-themed sites, but when we use a theme, we’d like our site to include the theme’s `src/pages` folder as well. To enable that, we use `gatsby-plugin-page-creator`. Run the line below to install, then create a new `gatsby-config.js` file and register the plugin there.

```sh
# eka-site-with-theme/gatsby-theme-hello-world
yarn add gatsby-plugin-page-creator
```

```js
// eka-site-with-theme/gatsby-theme-hello-world/gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: "gatsby-plugin-page-creator",
      options: {
        path: `${__dirname}/src/pages`
      }
    }
  ]
};
```

#### 4b) `gatsby-mdx`

[MDX](https://mdxjs.com/) is a new format that enables you to use JSX in your Markdown files. We’re going to add this plugin and its dependencies so Gatsby can read MDX files. Like with the previous dependency, we install the packages, open our config file, and add `gatsby-mdx` into the `plugins` array.


```sh
# eka-site-with-theme/gatsby-theme-hello-world
yarn add gatsby-mdx @mdx-js/mdx @mdx-js/tag @mdx-js/react
```

```js
// eka-site-with-theme/gatsby-theme-hello-world/gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: "gatsby-plugin-page-creator",
      options: {
        path: `${__dirname}/src/pages`
      }
    },
    `gatsby-mdx`
  ]
};
```

📝 **Note:** `gatsby-mdx` is just an example; feel free to substitute with other source and transformer plugins (for instance `gatsby-source-filesystem` and `gatsby-transformer-remark`) if you are familiar with them.


### 5. Add pages to THEME

Themes are regular Gatsby sites, so we can develop it as we normally do.

#### 5a) Home page

First, let’s create the `src/pages` folder and create `index.js` that exports a simple component that renders a heading text. This is the standard way to create a page using React component.

```sh
# eka-site-with-theme/gatsby-theme-hello-world
# create src/pages folder
mkdir src && mkdir src/pages 

# create index.js 
touch src/pages/index.js
```

```js
// eka-site-with-theme/gatsby-theme-hello-world/src/pages/index.js

import React from "react";
export default () => <h1>Theme Home Page</h1>;
```

#### 5b) "hello-theme" page

Second, make a file called `hello-theme.mdx` in `src/pages` and add some text. Here, we can use the MDX format because we already installed `gatsby-mdx`. In real use case, you are free to choose whichever best suits your needs.

```md
# Hello world from theme

This content is created from the `gatsby-theme-hello-world` theme.
```
<figcaption>eka-site-with-theme/gatsby-theme-hello-world/src/pages/hello-theme.mdx</figcaption>

Now let’s run our theme as a regular site to check whether everything works correctly. 

```sh
# eka-site-with-theme/gatsby-theme-hello-world
gatsby develop
```

Go to http://localhost:8000 and see our index page. Then go to http://localhost:8000/hello-theme to see our "Hello world" post.

![Page with title Theme Home Page](https://thepracticaldev.s3.amazonaws.com/i/vu7og9uonprv7i8cjrsy.png) ![Page with title Hello World from Theme](https://thepracticaldev.s3.amazonaws.com/i/pl2ih5grvgr4vh03ll7w.png)

#### 🌮 Extra: the `yarn workspace` way

Instead of using `gatsby develop` from the _theme_ folder as usual, we can also use the `yarn workspace` command from the workspace root. To do that, we need to add the `gatsby develop` command to the theme’s `package.json` file.

```js
// eka-site-with-theme/gatsby-theme-hello-world/package.json
{
  "name": "gatsby-theme-hello-world",
  // other things
  "scripts": {
    "develop": "gatsby develop"
  }
}
```

Now go to the workspace root folder and run this command.

```sh
# from workspace root (eka-site-with-theme)
yarn workspace gatsby-theme-hello-world develop

# is equal to this
# in theme folder (eka-site-with-theme/gatsby-theme-hello-world)
yarn develop
```

This also applies to any other `yarn` commands.

Now we’ve already got a working theme, time to create our site and use the theme from there!

### 6. Add dependencies (including the theme) to SITE

Go to our _site_ folder, then install our dependencies:
- gatsby
- react
- react-dom

```sh
# eka-site-with-theme/example-site
yarn add gatsby react react-dom
```

We are also adding our theme, `gatsby-theme-hello-world`, as a dependency. Since we are using a local theme, we can add it to `package.json` like so:

```js
// eka-site-with-theme/example-site/package.json
{
  "name": "example-site",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "gatsby": "^2.4.2",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "gatsby-theme-hello-world": "*"
  }
}
```

Just like with plugin dependencies in step 4, we are also adding our theme to `gatsby-config.js` in a similar manner. First create the file in our _site_ folder, and add the following:

```js
// eka-site-with-theme/example-site/gatsby-config.js
module.exports = {
  __experimentalThemes: [`gatsby-theme-hello-world`]
};
```

Now try running the app. Once the app is running, you should be able to access http://localhost:8000 and http://localhost:8000/hello-theme like we did from the theme.

### 7. Create a post in SITE

As a user, we’d want to add our own site content. We can do so by creating a file—let’s call it `hello-user.mdx`—in `src/pages`. This step resembles step 6 above, but we are doing this from the _site_ folder now.

```md
# Hello world from user

This content is created from the example user site.
```
<figcaption>eka-site-with-theme/example-site/src/pages/hello-user.mdx</figcaption>

Now run the app again, and head to http://localhost:8000/hello-user. You can see than in addition to the home page and the “hello-theme” page, we have a new page that only exists in our site.

![Page with title Hello World from User](https://thepracticaldev.s3.amazonaws.com/i/q6ntqqnqntibxmtmj8hz.png)


### 8. Add a ghost (optional)

A theme developer can integrate any necessary components for users’ convenience, so users don’t have to install and configure the components themselves. _(Also, this is really just an excuse to use the [miukimiu/react-kawaii](https://github.com/miukimiu/react-kawaii) library, which I’m quite smitten with.)_

Go back to the `gatsby-theme-hello-world` folder, run `yarn add react-kawaii` to intall the package.

Open the user post file `hello-user.mdx` and add a component from `react-kawaii`.

```mdx
import { Ghost } from "react-kawaii";

# Hello world from user

This content is created from the example user site.

<Ghost size={160} mood="happy" color="#f0f0f0" />
```
<figcaption>eka-site-with-theme/example-site/src/pages/hello-user.mdx</figcaption>

Now run the _example-site_ app again, and go to http://localhost:8000/hello-user. You should see your post with a ghost illustration underneath.

![Same page as Hello World from User above, but with ghost illustration](https://thepracticaldev.s3.amazonaws.com/i/e139aup77dhjhyr95512.png)

Thus, we have successfully built a theme and used it in our new site. Yay! 🎉 

---

## 📝 Notes and Thoughts

As usual, I’m sharing my (subjective!) thoughts about what I've been creating in this post. Feel free to chip in if you’ve got anything to add.

🤔 _**Isn’t this overengineering?**_

If you *only* need to create a “Hello World” page, YES, definitely! However, I do find the potential use cases—which you can find in the [links in my first post](https://dev.to/ekafyi/learning-gatsby-themes-introduction-1gje)—legitimate. I’m doing this kind of basic implementation to grok the principles before going into more complex (and more realistic) usage.

❓ _**Related to step 3 — I still have not understood peerDependency for themes.**_

What if my existing site uses eg. gatsby version 2.0.0 but the theme uses 2.1.1 as devDependency _and_  peerDependency? Will it force my entire site to run the theme’s copy of gatsby? Or just the part that uses the theme? What if my site uses another theme that uses eg. 2.0.0 as peerDepencency?

The setup I used in this post is used in [livestream-gatsby-themes](https://github.com/jlengstorf/livestream-gatsby-themes/blob/master/packages/gatsby-theme-livestream/package.json) and [gatsby-theme-carbon](https://github.com/carbon-design-system/gatsby-theme-carbon/blob/master/packages/gatsby-theme-carbon/package.json). However, other themes use different setup, such as [gatsby-theme-minimal](https://github.com/ChristopherBiscardi/gatsby-starter-theme/blob/master/gatsby-theme-minimal/package.json) (only `peerDependencies`) and [gatsby-theme-example-component-extending](https://github.com/johno/gatsby-theme-example-component-extending) (neither `dev` nor `peerDependencies`). If anyone could explain the rationale, I would be grateful.

---

That’s all for now, folks.

Up next: I’m going to continue developing the theme, demonstrating [Component Shadowing](https://www.gatsbyjs.org/blog/2019-04-29-component-shadowing/) and playing around with `gatsby-node.js` to create pages programmatically.

Stay tuned and thanks for reading! 🙌🏾