Running a Gatsby blog inside a Phoenix app

logicmason profile image Mark Updated on ・3 min read

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
  • 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:

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

Posted on by:

logicmason profile



Education enthusiast. Ex Groupon Merchant Engineering, Engineering and Growth at Verbling (YC'11) and cram school founder in Taiwan. Currently building Alchemist Camp.


markdown guide