Introducing Dotenv Validator: A Lean Library to Validate your Environment Variables

Introducing Dotenv Validator: A Lean Library to Validate your Environment Variables

We are excited to share a new gem for the Ruby community: dotenv_validator! A library that will help you validate that the values in your environment are valid according to the comments in your .env.sample file.

  1. Problem
  2. Solution
  3. Caveats
  4. Final Thoughts (TL;DR)

1. Problem

At OmbuLabs (the company behind FastRuby.io) we embrace the Twelve-Factor Methodology for all of our internal, open source, and client applications. One of the principles of this methodology is to store configuration in the environment.

The twelve-factor app stores config in environment variables (often shortened to env vars or env). Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.

We have been using the dotenv gem for years and we really like it. It works like this:

  1. You define a .env file in your application directory
  2. Dotenv loads them before loading your application code
  3. Then you can use those values like this ENV['DATABASE_URL']

Unfortunately it doesn’t help you validate that you have all the environment variables that you need to run an instance of your application. So sometimes you end up with cryptic messages when you try to boot your Rails app without all the right environment variables.

2. Solution

When designing this library, we took into account another file that has been very useful over the years: .env.sample

The goal of the sample file is to help new developers get started with your application. Our bin/setup scripts usually look like this:

puts "\n== Copying .env file =="
unless File.exist?('.env')
  FileUtils.cp '.env.sample', '.env'
end

Source: bin/setup from skunk.fyi

Basically, if the .env file does not exist it will use the .env.sample file to create the .env file.

An .env.sample may look like this:

.env.sample
ADMIN_USERNAME=foo # required
ADMIN_PASSWORD=bar # required

The comments at the end of each line do not get loaded by Dotenv, so they can be used for documenting details about the variables (e.g. date format, length)

We decided to use this documentation “as executable code” which will be interpreted by DotenvValidator.

Every time someone adds a new variable to the application, they must:

  1. Add a line to the .env.sample file with the right comment
  2. Add a reference to the environment variable somewhere in the application

For example, when we launched the landing page for our roadmap package (a code audit to plan your next upgrade project), we decided to add these two new variables:

# .env.sample
ROADMAP_PRICE=3900 # required,format=int
DISCOUNT_AMOUNT=500 # required,format=int

We were already using dotenv to load our env variables. So then we only had to add dotenv_validator to our Gemfile:

gem "dotenv_validator"

Then we had to add this file to our initializers directory:

# 01_dotenv_validator.rb
puts "Validating environment... 🧐🧐🧐"
DotenvValidator.check!
puts "Your environment is in good shape! 🚀🚀🚀"

The name of the file is important: We named the file so that it is the first initializer it runs. This is the safest way to go because other initializers may depend on environment variables.

When we tried to load the application without the right environment variables, this is what we saw:

Validating environment... 🧐🧐🧐
Exiting
/Users/etagwerker/Projects/fastruby/dotenv_validator/lib/dotenv_validator.rb:73:in `check!':
Missing environment variables: ROADMAP_PRICE, DISCOUNT_AMOUNT

No more cryptic messages! Now you can quickly learn that the app won’t work as expected if you don’t set the right environment variables.

Borat is happy and so is our environment!

DotenvValidator stops the boot process and makes us add the right environment variables to our .env file.

3. Caveats

In order to use dotenv_validator you have to keep a .env.sample in the root of your application directory. That file should be checked in to the repository and updated accordingly every time you add (or remove) an environment variable.

Comments need to use the following syntax:

  • # required for environment variables that must be in your environment before you can run the application.

  • # format=email for environment variables that must have a particular format. There are many supported formats for your variables (it even supports regexps!)

  • You can combine rules like this: # required, format=email

Using .env.sample was a design decision. We didn’t want to add yet another file or DSL to our applications. If you are okay with that, envied is a pretty cool solution for the same problem! 🤓

4. Final Thoughts

This new gem is quite lean (less than 120 lines of code) and it solves the problem of missing or invalid environment variables in your environments. It’s pretty straight-forward and it relies on existing best practices:

  • Using environment variables
  • Keeping a .env.sample file in your repo to document them

If you’ve been bitten by missing environment variables in the past, give it a try and let us know what you think!

Finally if you want to get started with open source we have a list of beginner-friendly issues on GitHub.

Thanks for reading all the way to here and thanks to all the contributors who helped with this gem! You rock. 🤘

Get the book