Environment Variables not updating in Release

In my code I have something like this.

@some_token System.get_env("SOME_TOKEN") || raise "Missing SOME_TOKEN"

The variable is inside the .env_prod file, I’ve also tried placing the variable in /etc/environment:.
When I do a release with:

source .env_prod
PORT=80 MIX_ENV=prod mix release --overwrite

The variable seems not to be updating, could it be caching? I’ve also tried connecting to the iex of the release by:

_build/prod/rel/mycode/bin/mycode remote

And check the variable:

System.get_env("SOME_TOKEN")

What could I be missing?

Module attribute @some_token gets resolved during the compile time. So once the release is built - it will not refetch the value from the System env variables.

Essentially you want to have a function in the module:

defp some_token do
  System.get_env("SOME_TOKEN") || raise "Missing SOME_TOKEN"
end

And then in the module instead of @some_token use some_token()

That will call System.get_env/2 on every call of some_token() just like when you tried in iex.

However, the better approach would be to use the runtime configuration (see more Configuration and releases - The Elixir programming language)

in config/runtime.exs add:

import Config

config :my_app, :some_token, 
  System.get_env("SOME_TOKEN") || raise "Missing SOME_TOKEN"

and use one of the functions from Application module to get the configured value in the module, for example

defp some_token, do: Application.fetch_env!(:my_app, :some_token)

This approach is better, at least because now it will fetch env variable from the system only once on app start and then store it internally. (no need to fetch the system on every function call)

4 Likes

Many reasons why this might fail - first question would be, are you sure you are compiling this app on the same server environment?

Second thought would be to not rely on ENV vars, but Application vars and set the vars in a secret production file, only available on the compiling server, and on the production servers.