DEV Community

Adam Rogers
Adam Rogers

Posted on

Bridgetown and Environment Variables

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'] %>
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
whysthatso profile image
Andreas Wagner

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?

Collapse
 
rodreegez profile image
Adam Rogers

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?

Collapse
 
whysthatso profile image
Andreas Wagner

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.

Collapse
 
katafrakt profile image
Paweł Świątkowski • Edited

Neat. I'm currently moving my blog from Jekyll to Bridgetown, so I'm hungry for all this kind of tips.