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.
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. 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 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'
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.
# .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.
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:
<%# /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?
Top comments (4)
i might miss something, and it's not really related to the whole env var business, but why would you keep client-side api keys out of a git repo?
Ultimmately I think the answer is because it's configuration, not code.
If I want to rotate my api key for a given service, should that require a full re-deploy of the website? In a static build like Bridgetown then yes, you are going to have to basically re-deploy the website and that is likely a tivial task, but in more complex environments that might be more difficult.
For me, I think that seperation of code and config represents something of a best practice, which I wanted to emulate in Bridgetown.
Keen to here your take. Would you argue for just slamming the api key in the html and being done with it?
yes, separation makes perfect sense, and should be considered as default certainly. i've seen too many frontend projects - usually by single developer - that leave configuration all over the place, ad hoc inserts, etc. it's very frustrating to take over a project like that and grep the code for config locations.
my angle was more geared towards the security aspect, as the key is public anyway.
Neat. I'm currently moving my blog from Jekyll to Bridgetown, so I'm hungry for all this kind of tips.