Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Copy link

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
You can’t perform that action at this time.