Often when developing apps with Rails you need to set up environment variables to keep sensitive information secure in your code. This article looks at how to set up environment config variables in Rails. We’ll look at why we need to store environment variables and look at various implementations. Finally, we’ll discuss the pros and cons of each solution.
Why Configuration Variables?
In your Rails application, you’ll usually have sensitive information like passwords, API keys or configuration data such as the URL end point of your data feed. Hard coding those and committing them into source control can be dangerous as it means anyone with access to your code can see your API keys and secrets. If you set them as environment variables, however, they will be set on operating system level in an environment that your application has access to, but not directly coded in the app’s source code – this way, your secrets stay secret from prying eyes.
Let’s look at a few ways to manage environment variables in Rails.
Using Bash or Zsh Profile
This is the “bare minimum” solution. You can store the environment variable key/value pairs with the operating system directly and globally, so they are going to be available to the Rails app. In your
.bashrc file or
.zshrc file, set environment variables with lines like:
With this, you can fire up rails console or
irb and access your environment var by doing:
ENV["KEY"] => "value"
This is all well and good but over time, your config file might get cluttered with so many of these variables and you’ll end up with one very messy global space. This is also not very ideal for creating app-specific environment variables or using different environment variables for different environments such as development and testing. Things will start getting messy. Enter the dotenv gem.
dotenv solves the problems of setting project-specific environment vars and is super easy to get started on. Start by including the
gem 'dotenv-rails', :groups => [:development, :test] in the appropriate groups, in this case development and test. You can then put your sensitive information inside a
.env file at the root of your project directory:
1 2 3
You can call these variables anywhere in your Rails application by using:
export (for accessing these variables in the terminal) and yaml-like configs come baked in. Make sure to git-ignore your
.env files if you’re working alone or you’ll be back to square one. While working on a team, you can maintain a default
.env.example file that is checked into source control with further instructions to other developers. This is to let other develops see what can be done. See dotenv docs for more.
Note: You can also use
.env file with foreman to manage your environment variables. Do not commit
.env to source control – it contains information and should be used in development only.
Figaro is similar to dotenv. What it does is to allow you to store all your sensitive secrets in a YAML file at
config/application.yml. With it’s simple
figaro install command you get your YAML file automatically added to
gitignore. Figaro is built with deployment to Heroku in mind. There is a handy configuration to help set values from your configuration file. It also provides helpful information on deploying to other hosts. It’s very nice to be able to do
figaro heroku:set -e production to set
ENV variables when deploying to heroku.
Very similar to Figaro’s
secrets.yml was added to Rails 4.1. You’ll have to add your secrets in
config/secrets.yml as is done with Figaro. The variables added here are accessible through
Rails.application.secrets. The first advantage is enhanced security. By default, the file contains the application’s
secret_key_base which prevents session tampering. Next there is no need for any external dependency; this has become part of Rails now and is easy to get started on. With this approach, we’ll have to remember to add it to
.gitignore. But how do we sync this configuration file with our production environment if the file is checked out of source control? Getting this done can involve going through a few hoops or even using external dependencies like this; it all ends up being a bit tedious. Although this solution is not perfect, we hope these problems will be resolved in future versions of Rails.
If you don’t want to use a gem to separate sensitive information from your project, there is a common pattern to create simple YAML files. You can name it
private.yml. You would store sensitive information here and remember to add the file to your
.gitignore, so that you don’t accidentally commit to source control. There are simple Railscasts here and here on how to get started.
How do I choose?
Using Bash or Zsh profile to store environment variables is akin to messing with system configuration files in order to store sensitive information. This approach allows you to set system wide and user specific environment variables. The major red flag with this approach is, as your configuration grows and becomes more complex, things will become a mess as you have to keep everything updated.
You’ll typically go for dotenv or Figaro to manage your app-specific secrets; they solve similar problems and are well-maintianed. Both are inspired by Twelve-Factor App’s concept of proper configuration. Apart from similarities discussed above, you’ll have to remember to add your
.env file to
gitignore when using dotenv. Figaro does this for you because of its convention of never committing configuration files. Also, Figaro expects a simple file for setting environment variables, meaning you have a single source of truth for all app configurations that’s easy to manage and reason about. dotenv provides support for separate files for each environment.
The addition of
secrets.yml to Rails 4.1 is a major step in the right direction and also does a very good job at managing app-specific environment variables. Use this if you don’t want any third-party dependencies in your app. One thing to note is, it does not follow the Twelve-Factor App’s concept of proper configuration in development. Environment variables are accessed through
Rails.application.secrets instead of
ENV which is a language and OS agnostic standard.
secrets.yml encourages using
ENV for production only. Further, in terms of security
secrets.yml is like dotenv in that your secrets are committed to source control by default.
Using a simple YAML file is the way to go if you want zero gem dependencies for managing environment variables. You’d have to write your own code to use the variables with Ruby’s standard library to parse YAML.