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:
- Startup, when using mix to run the app
- 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