This afternoon I had a bit of a time getting environment variables working in my first real stab at a Bridgetown site. I'm not sure I've figured out the best way to do this, but here's what I came up with.
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.
I usually make Rails applications, and with Rails applications I usually use 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.
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 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:
# /plugins/env.rb require 'dotenv/load'
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.
# .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.
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?
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:
<%# /src/_layouts/home.html.erb %> <%= ENV['MY_API_KEY'] %>
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?