Ruby on Rails: Manage local environment variables with dotenv

I mentioned how I prefer using environment variables to tailor the configuration of my Ruby on Rails app rather than going by the environment’s name. Here, I explain how I manage environment variables for a specify app using dotenv. (Figaro does a similar job – it’s mostly a matter of preference.)

Using dotenv means you can apply specific environment variables only to an app. You do not need to change the environment variables of your shell.

Like the README page linked above states, the simplest usage of dotenv is to add it wrapper tailored for Rails to your Gemfile for development and testing:

gem 'dotenv-rails', :groups => [:development, :test]

Update the bundle installation:

$ bundle

Set the environment variables you wish to use in your app in a .env file in your app’s root directory:

S3_BUCKET=YOURS3BUCKET
SECRET_KEY=YOURSECRETKEYGOESHERE

Then, run the app:

$ rails s

That works.

But there’s one detail I had to deal with. Since the .env file may contain sensitive information, I do not commit it in the repo. That itself isn’t a problem, but the file’s name is interfering with the default file used by heroku-config, which I sometimes use to manage my environment variables on Heroku. There’s a risk to overwrite that file, and I’m just too lazy to go around browsing through old messages for API keys just to rebuild it.

Also, what if I simply want to fetch the environment variables of production into another .env file, and use it to start my app and test it as it should run on production?

Luckily, dotenv has a nice undocumentated feature which will load .env files based on the environment. For example, .env.development will be automatically loaded for development, .env.staging for staging, and so on.

But sadly, that feature is deprecated. Using it will warn you of such. You may update the gem one day, and poof, that feature won’t work anymore!

“Okay… Well, I guess I’ll deal with that.” Besides, aren’t those .env.* files in the root directory starting to get messy?

Here is the setup I propose:

  • First, create a directory for all your .env files:

    $ mkdir config/env
    
  • Write an example of a .env, with no sensitive information, in config/env/development.env.example. That file will be commited in the repo.
  • Use the file you just made as a template. Fill it with the environment variables you wish to use locally, and save it as config/env/development.env. That file will not be commited in the repo.
  • Add the following lines in .gitignore to ignore all .env files except the example:

    /.env
    /config/env/*.env
    
  • Install the dotenv gem – not dotenv-rails – only for development and testing by adding this to your app’s Gemfile:

    gem 'dotenv', groups: [:development, :test]
    
  • Run bundle to install it.
  • Load dotenv and the appropriate .env file when available by adding the following at the bottom of config/boot.rb:

    # Import environment variables when dotenv is available
    if Gem::Specification.find_all_by_name('dotenv').any?
      require 'dotenv'
      Dotenv.load "config/env/#{ ENV['RAILS_ENV'] || :development }.env"
    end
    

    This will make sure to only load the gem if its installed, so it will load it on development, but will not raise an error on production. Nothing will break if no .env file is available either.

There you have it! Run your test, add the files, and commit.

The way it is setup now is just as automatic as before, and the files are tucked into config like I feel all configuration files should, without messing up your root directory with hidden files.

You go and play with those env vars!

2 thoughts on “Ruby on Rails: Manage local environment variables with dotenv

Leave a Reply