Configuration is one of the rougher edges of the Elixir ecosystem even after the many improvements over the years. Because it's always been rough, you may not expect, and therefore miss, the hidden improvements nested in recent Elixir releases. This post will shine a light on ways to leverage these improvements for better configuration. Note on terminology:

  • “application environment” refers to application variables that are accessible with Application.get_env and are generally set with Config.config by elixir scripts inside the config directory.
  • “environment variables” are part of the environment in which an Operating System process runs (see environment variables on Wikipedia). In Elixir environment variables can be accessed via System.get_env and System.put_env (plus a couple other functions). A brief history of configuration in Elixir At one point it was a recommended practice to read application environment variables at compile-time (technically build-time) with module attributes. For example: This was recommended for the following reasons:
  • This is similar to a common pattern in Ruby/Rails with instance variables.
  • There’s a (very small!) performance benefit in not reading configuration on every function call.
  • Note: Application env is backed by :ets which is stored in-memory and is very fast, but if you have a very tight loop or performance critical code you may want to either cache the configuration value in process state or look into :persistent_term. Despite this being recommended, I got the sense that relying on environment variables is generally frowned upon in the wider Elixir community. The community preference was to write application configuration scripts directly. This is why, at the time, Phoenix would generate a config/prod.secret.exs in fresh Phoenix projects. This file isn’t generated in newer versions of the Phoenix generators since the configuration style has been refined. In my experience, using configuration scripts...