Warnings about Application.get_env/2 when using environment variables for configuration

I have an Elixir/Phoenix app which I build with Docker, and I’d like to have the configuration coming from environment variables so that I don’t need to rebuild and deploy to make configuration changes. I’m using Application.get_env (which I use to set module level constants), but it results in warnings (about using it in the module body) which make me think I’m missing a better approach.

example code

config

  #...
  some_setting = System.get_env("APP_SOME_SETTING")
  config :test_app, :some_setting, some_setting
  #...

app module somewhere

defmodule Test.App do

  @some_setting Application.get_env(:test_app, :some_setting)

  #... (functions using the config)

end

Perhaps someone could help me with a better pattern here?

The warnings are likely suggesting you use Application.compile_env instead, because that clarifies when the value is actually read from the environment.

I’d like to have the configuration coming from environment variables so that I don’t need to rebuild and deploy to make configuration changes.

If you want to do such a thing, you shouldn’t put it in module attributes (like @some_setting) because these are compile-time. You’re evaluating the function and putting whatever it results in the attribute.

Instead, you can use

def my_config() do
  Application.get_env(...)
end

But notice that config/config.exs is evaluated at:

  1. Startup, when using mix to run the app
  2. Compile time, when using releases.

And config/runtime.exs is always evaluated at startup.

So if you want to simply restart the app with a new environment, without recompiling, you should use config/runtime.exs (and, again, not module attributes). Another alternative is simply calling System.get_env/2 in runtime.

To change application config in runtime, without restarting the app, you should use something like Application.put_env/3.

6 Likes