myl
What is the cleanest way to load and parse en vars during both configuration and execution?
Hi everybody,
First, I am very new to Elixir and to this forum. Please forgive me if my english is bad or if I transgress any rule ![]()
I need to find a clean way to load environment variables during both configuration and execution phases, to configure the app depending on the environment (prod/dev/etc).
My new team already uses an imperfect solution :
At runtime, we dynamically load environment variables depending on the environment the app is running, thanks to an in-house helper (env.ex) that fetch the env var and parse it to verify its format.
As some of this vars are required on configuration phase, the module is compiled a first time from config.exs, and some variable are loaded later from the config.exs file (second parameter is a default value):
Code.compile_file("lib/our_app/utils/env.ex")
[...]
secondapp_server_url: Env.load("SECOND_APP_URL", "http://localhost:3001")
This solution is working, but the env.ex module is compiled a second time later (during the app compilation), resulting in a warning (double compilation) that we want to get rid of.
Also, they brainstormed before my arriving and concluded that this module has been very useful to them, so they’d like to keep it.
First, we thought that we simply had to put our env.ex in its own new hex package and add it as a dependency to our app. Doing so, I discovered by running mix deps.get that the configs.exs is parsed before deps are fetched and compiled. Thus, the mix deps.get command is crashing:
$ mix deps.get
** (UndefinedFunctionError) function Env.load/2 is undefined (module Env is not available)
Env.load("SECOND_APP_URL", "http://localhost:3001")
(stdlib 3.17) erl_eval.erl:685: :erl_eval.do_apply/6
(stdlib 3.17) erl_eval.erl:893: :erl_eval.expr_list/6
(stdlib 3.17) erl_eval.erl:237: :erl_eval.expr/5
(stdlib 3.17) erl_eval.erl:229: :erl_eval.expr/5
(stdlib 3.17) erl_eval.erl:230: :erl_eval.expr/5
(stdlib 3.17) erl_eval.erl:893: :erl_eval.expr_list/6
(stdlib 3.17) erl_eval.erl:408: :erl_eval.expr/5
I can’t find the best way to keep this module for both configuration and execution purpose (I believe transforming it in a .exs file would not make it), or which better practices I should follow to replace it.
So any help would be appreciated !
Thank you !
Marked As Solved
Nicd
Tooting my own horn here, but I’ve written a blog post that describes a system of configuration that I personally use, where you have the same configuration in development and production: Simple Configuration Setup for Elixir Projects (v1.11+) – Random Notes – Reading it may provide you with some new thoughts.
But to summarise, you can probably move most of your config to config/runtime.exs like LostKobrakai said. This file is evaluated both in development and production when your system starts up. In that file you can also use your Env module without any issues, as it has already been compiled at that point (just like I use my own env helpers in my blog post). The rest of the “classic” config/*.exs files are for compile time configuration, which is not needed for most things you want to configure.
If you need environment variables in compile time configuration for some reason, then what you are doing now (with the double-compilation warning) is probably the best you can do.







