View Source Cheatsheet

Quick reference for using Dotenvy.

Setup

envs/ Directory

The recommended location for storing your .env files is inside a dedicated envs/ directory. Code editors recognize the .env extension.

Example envs/dev.env

LOG_LEVEL=debug
AWS_REGION="us-east-1"
HTTP_CLIENT=HTTPoison

Version Control

envs/dev.env is tracked by Git. Use it to store sensible non-sensitive defaults.

envs/dev.local.env is ignored by Git. Use it to override any variables in the tracked version.

This must match the values used in the runtime configuration.

.gitignore

*.local.env

Release Compatibility

For compatibility with releases, configure your builds to copy (i.e. "overlay") the contents of your envs/ directory into the root of the release.

mix.exs

defp releases do
[
    my_app: [
    include_executables_for: [:unix],
    steps: [:assemble, :tar],
    overlays: ["envs/", "priv/", "config/"]
    ]
]
end

Runtime Config

Your config/runtime.exs is where you source your environment variables. The last argument to Dotenvy.source/2 or Dotenvy.source!/2 takes precedence. It's common to use System.get_env() as the final argument so any existing system environment variables will take precedence over anything parsed from the .env files.

config/runtime.exs

import Config
import Dotenvy

dir = System.get_env("RELEASE_ROOT") || "envs/"
# In an umbrella app:
# dir = System.get_env("RELEASE_ROOT") || Path.expand("./envs/") <> "/"
  
source!([
  "#{dir}#{config_env()}.env",
  "#{dir}#{config_env()}.local.env",
  System.get_env()
])

Example Database Configuration

Dev ENV

envs/dev.env

PG_USERNAME=postgres
PG_PASSWORD=postgres
PG_HOSTNAME=localhost
PG_PORT=5432
PG_DATABASE=m_app_dev
PG_POOL_SIZE=10
PG_POOL=DBConnection.ConnectionPool
PG_SSL=true

Test ENV

envs/test.env

PG_USERNAME=postgres
PG_PASSWORD=postgres
PG_HOSTNAME=localhost
PG_PORT=5432
PG_DATABASE=my_app_test
PG_POOL_SIZE=10
PG_POOL=Ecto.Adapters.SQL.Sandbox
PG_SSL=false

Runtime Configuration

config/runtime.exs

import Config
import Dotenvy

dir = System.get_env("RELEASE_ROOT") || "envs/"
  
source!([
  "#{dir}#{config_env()}.env",
  "#{dir}#{config_env()}.local.env",
  System.get_env()
])

config :my_app, MyApp.PGRepo,
  pool: env!("PG_POOL", :module?),
  pool_size: env!("PG_POOL_SIZE", :integer),
  database: env!("PG_DATABASE", :string),
  username: env!("PG_USERNAME", :string),
  password: env!("PG_PASSWORD", :string),
  port: env!("PG_PORT", :integer),
  hostname: env!("PG_HOSTNAME", :string)

Transformations

System Environment variables are always stored as strings which may need to be transformed into native Elixir data types.

Used as the 2nd argument to Dotenvy.env!/2 and Dotenvy.env!/3

Conversion TypeElixir TypeOn Empty String
:atomatom:""
:atom?atomnil
:atom!atomraise ⚠
:booleanbooleanfalse
:boolean?booleannil
:boolean!booleanraise ⚠
:charlistcharlist'' i.e. []
:charlist?charlistnil
:charlist!charlistraise ⚠
:integerinteger0
:integer?integernil
:integer!integerraise ⚠
:floatfloat0
:float?floatnil
:float!floatraise ⚠
:existing_atomatom:"" or raise
:existing_atom?atomnil
:existing_atom!atomraise ⚠
:moduleatom:"Elixir."
:module?atomnil
:module!atomraise ⚠
:stringString""
:string?Stringnil
:string!Stringraise ⚠

Custom functions handle their own behavior.

Custom Function Example

PHX_IP="0, 0, 0, 0, 0, 0, 0, 0"
config :feenix, FeenixWeb.Endpoint,
    http: [
      # Enable IPv6 and bind on all interfaces.
      ip: env!("PHX_IP", fn ip -> 
        ip 
        |> String.split(",") 
        |> Enum.map(&String.trim/1) 
        |> Enum.map(&String.to_integer/1) 
        |> List.to_tuple()
      end)
    ],

Your custom functions can raise a Dotenvy.Error to benefit from improved messages that include helpful context about any problems, e.g.

strict_boolean! = fn
  "true" -> true
  "false" -> false
  _ ->
    raise Dotenvy.Error,
      message: "strict_boolean! values must be either true or false"
end

config :myapp, :some_bool, env!("SOME_BOOL", strict_boolean!)

This will yield an error like the following:

** (RuntimeError) Error converting variable SOME_BOOL using custom function: strict_boolean! values must be either true or false