Running a Gatsby blog inside a Phoenix app
Tags: setup, phoenix, staticassets, gatsby
Published: 2019-10-07 02:35:15

---
title: Running a Gatsby blog inside a Phoenix app
published: true
description: It's usually trivial to serve a static site, but it can be a pain to get Gatsby to output things where another framework needs them. Here's how I integrate a Gatsby blog with a Phoenix site: 
tags: Setup, Phoenix, Static Assets, Gatsby
canonical_url: https://alchemist.camp/articles/gatsby-phoenix
---
Let's see what it takes to set up a Gatsby blog inside a Phoenix app!

Like Jekyll, VuePress and other popular static site generators, Gatsby is a easy way to create a snappy blog. Since it generates plain HTML, CSS and JS (aka "a static site"), all that's really needed is to drop the files in a directory that serves static contents.

By default, Phoenix includes a directory for serving static assets at `/assets/static`. Any files and subdirectories named in the `only:` key of `Plug.Static` inside your `endpoint.ex` file will be loaded from this static assets directory instead of being delegated to your router.

## Initial Setup
- Make sure you've [installed Node, Elixir and Phoenix](https://alchemist.camp/episodes/asdf-language-versions)
- Install the Gatsby CLI: `npm install -g gatsby-cli`
- Create a new Phoenix app: `mix phx.new my_app`
- Go into the newly created directory: `cd my_app`
- Generate the DB: `mix ecto.setup`
- Go into the assets directory (of your new app): `cd assets`
- Create a Gatsby site inside `assets`: `gatsby new gatsby https://github.com/gatsbyjs/gatsby-starter-hello-world`

## Verify the installations were successful
At this point, you should be able to start your Phoenix app by running `mix phx.server` from the base of your project, the `my_app` directory and opening `localhost:4000` in your web browser.

The static site generated by Gatsby can be run in development mode by running `gatsby develop` from `my_app/assets/gatsby` and then opening `localhost:8000`. It's just a "Hello world!" for now.

We named the site "gatsby" in the previous section so that it's clear, from the context of the enclosing Phoenix project, that this is a Gatsby site. 

## Generate the static site
In order to run the static site in production, we'll want to build a production bundle. The command to do it is `gatsby build`. By default this will build the site under a directory called "public", which in our case will be at `my_app/assets/gatsby/public`.

This isn't ideal.

We need to serve the output of the Gatsby build from our Phoenix static assets directory, but don't want to serve our Gatsby project's `src` or other directories publicly. There is an `--output-dir` flag that can be passed to the `gatsby build` command, but at the time of this writing, it's not possible to pass an output directory outside the Gatsby project, only the name of the directory is configurable.

## Create a symlink
One way to get around this issue is to create a symlink from Gatsby's output directory to the static assets directory. First cd into the `/my_app/assets/static` directory, and then...

- On Unix or Mac: 
```
ln -s ../gatsby/public blog
```
- On Windows:
```
mklink ..\gatsby\public blog
```

Now, the entire contents of whatever is generated in Gatsby's public output directory will be visible as a "blog" directory under the Phoenix static assets directory.

## Enable the blog directory
The final step is to open up `endpoint.ex` and update the `Plug.Static` portion near the top to allow it to handle the newly created blog directory (which is a symbolic link of the Gatsby public directory). It should look like this:

```elixir
defmodule MyAppWeb.Endpoint do
  use Phoenix.Endpoint, otp_app: :demo

  socket "/socket", MyAppWeb.UserSocket,
    websocket: true,
    longpoll: false

  plug Plug.Static.IndexHtml, at: "/blog"

  plug Plug.Static,
    at: "/",
    from: :demo,
    gzip: false,
    only: ~w(blog css fonts images js favicon.ico robots.txt)

  # The rest of the file
```

After saving these changes, and restarting the Phoenix app, the generated Gatsby site is served from within the Phoenix app at `localhost:4000/blog/index.html`.

## Possible next steps
Now that everything is up and working, You could just build out the web app and static blog. For many apps and sites, no further integration is necessary.

Here are some ideas, though...

1. See if you can write a simple plug that will read the path from `conn.request_path` and redirect `/blog/` to `/blog.index.html`. Or alternatively, you could look at a library `plug_static_index_html` and see if you can use it to handle this for you.

2. Try installing Absinthe GraphQL and serving your static Gatsby blog GraphQL from the Phoenix back-end. This is a fairly large endeavor, but it's a great learning experience!

*Request a free email-based Elixir course from [Alchemist.Camp](https://alchemist967856.typeform.com/to/FA0SUF)*