Skip to content

Instantly share code, notes, and snippets.

@matthewoden
Created February 21, 2017 20:27
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewoden/4c109b627a36e41de9ed5e15cb615edf to your computer and use it in GitHub Desktop.
Save matthewoden/4c109b627a36e41de9ed5e15cb615edf to your computer and use it in GitHub Desktop.
Handling Environment variables in elixir

####david.antaramian in @elixir-lang slack, #beginners [2:11 PM]

Just in case you need it for reference in the future, this is the problem we normally see people run into: People will sometimes have called the environment variable during a module attribute assignment. Like the following:

defmodule MyAPP.APIClient do
  @api_key System.get_env("API_KEY")
end

or more commonly, they'll call the System.get_env/1 inside a config file and then assign the result to a module attribute:

# config/config.exs
config :my_app, :api_client,
  api_key: System.get_env("API_KEY")

# lib/my_app/api_client.ex
defmodule MyAPP.APIClient do
  @api_key Application.get_env(:my_app, :api_client)[:api_key]
end

The trick is that Elixir is a compiled language, and that module attribute are evaluated at compile time. So whatever the value of that environment variable is at compile time (or nil if it doesn't exist), becomes the value used throughout the file for that attribute until the module gets recompiled. I've seen this issue with people running on Heroku where they expect to have their API Key be fetched dynamically, but because the environment variable wasn't present when the slug was compiled, the code always just reports nil as the API key.

For this reason, it's useful to use scripts like this one from Bitwalker: https://gist.github.com/bitwalker/a4f73b33aea43951fe19b242d06da7b9

This makes the environment variable be fetched at the last minute when used correctly.

And it's release-safe. System.get_env/1 (or any other function calls) are not release safe in config.exs

@matrinox
Copy link

matrinox commented Jan 29, 2018

Is there a solution that would work for non-user applications such as exq or ecto? To my knowledge, you can only configure them via sys.config in a compiled application. I know of an alternative that uses Erlang options but I was wondering if you knew of a cleaner approach.
EDIT: I also know about RELX_REPLACE_OS_VARS, which only works with string values. This falls apart when dealing with ports or pool size, for example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment