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
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:
- You define a
.env
file in your application directory - Dotenv loads them before loading your application code
- 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:
- Add a line to the
.env.sample
file with the right comment - 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.
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. 🤘