View Source Cheatsheet

Quick reference for using Dotenvy.

setup

Setup

envs-directory

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

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

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

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/"
  
source!([
  "#{dir}#{config_env()}.env",
  "#{dir}#{config_env()}.local.env",
  System.get_env()
])

example-database-configuration

Example Database Configuration

dev-env

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

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

Runtime Configuration

config/runtime.env

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

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)
    ],