Bridgetown and Environment Variables
Tags: bridgetownrb, ruby, erb, dotenv
Published: 2020-12-07 19:57:11

This afternoon I had a bit of a time getting environment variables working in my first real stab at a [Bridgetown](https://www.bridgetownrb.com/) site. I'm not sure I've figured out the best way to do this, but here's what I came up with.

## Background
It's worth pointing out a few related background details:

* I am a curmudgeon and I do not like change, so I switched the templating in my site to `erb`, which I believe is a relatively new feature of Bridgetown, but a relatively old feature of Rails.
* I want to be able to set env vars locally, keep them out of my git repo, and set different ones in production in whatever way is apropriate for whatever production is.
* I don't want my application code to care about what environment it's running in.

## dotenv
I usually make Rails applications, and with Rails applications I usually use [dotenv](https://github.com/bkeepers/dotenv). This allows me to have a `.env` file that gets loaded when my Rails app boots. In Rails-land, we can use `dotenv-rails` which will hook into the application boot process and bootstrap our environment variables for us. This mostly works fine, but you can mess with it if you need to. Yay for Rails, I guess.

## Bridgetown is not Rails
How, then, to hook the loading of env vars into the build process? After a bit of messing about and a nudge from the nice people on the [Bridgetown discord server](https://discord.gg/V56yUWR) I discovered that one can write "plugins" for Bridgetown. Getting `dotenv` to play nice with bridgetown was as simple as `bundle add dotenv` and then creating the file `/plugins/env.rb` that required the gem:

```ruby
# /plugins/env.rb
require 'dotenv/load'
```

## Setting Env Vars
With `dotenv` being required, any `key=value` pairs we put in a file called `.env` located at the route of the project will be loaded into the environment when Bridgetown builds.

```ruby
# .env
MY_API_KEY=ABC123
SOME_OTHER_KEY=DEF246
```

You're not limited to `.env` files, either. `dotenv` allows you to set key-value pairs in a whole bunch of different files, and will load each in [an order of precidence](https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use).

## Keeping API keys out of git
Obviously the whole point of this exercise is to keep our precious API keys out of git. To do this, I like to add `.env` to my `.gitignore`, duplicate the file and rename it to `.env.example` and then replace all the keys in `.env.example` with nonsense. I do this on basically every project so when I see a `.example` file I know I need to copy it to the real file, but you may want to add a reminder to your `README` or similar.

Pro tip: do this _before_ you commit any of your `dotenv` stuff to git, else you'll have to look up how to make git forget about the original `.env` file and who's got time for that kind of nonsense?

## Reading Env Vars
Now that we have Env Vars being set and loaded, we can read them in our views. As mentioned I'm using `erb`, so that should look pretty familiar to anyone who's done a little Rails:

```erb
<%# /src/_layouts/home.html.erb %>
<%= ENV['MY_API_KEY'] %>
```

## Why did you do this?
Static sites generally and Bridgetown particularly allow us to build "Jamstack" sites that leverage third-party APIs from the client side, and eschew a server entierly. In order to access an API though, you'll typically need to access an API key. Think Stripe API keys, Google Analytics API keys, Mapbox API keys... anything like that. 

Bridgetown does have a mechanism, two in fact, for loading arbitrary key-value pairs at build time, but neither felt like a particularly suitable place to put API keys. 

`config.bridgetown.yml` exists and you could add keys there, however this is the global config for Bridgetown, which means you would find it trickier to do the whole `.example` trick to keep your keys out of git, and if you did you'd have to copy your whole config across which seems like it'd be just itching to get out of sync.

You can also add keys to the `site.data` object in Bridgetown by creating e.g. `/src/_data/env.yml`. This would make our keys available through e.g. `site.data.env.MY_API_KEY`, but that felt like abusing a function meant for something else.

At the end of the day, I only really need to dump the right value for a given key onto the page interpolated into some JS snippit or other, and Env Vars seem like the right place to do that.

How do you load API keys into your Bridgetown site?