teamon

teamon

Runtime configuration only for production

Context

I have a small team working on one elixir application.

Every developer runs the app locally.

The app is built with mix release inside docker on CI and deployed as a container.

Over time, we’ve settled on this approach to configuration files:

  • config/config.exs provides a common build-time configuration base for all dev/test/prod
  • config/dev.exs provides a build-time configuration for all developers
  • config/dev.local.exs gives a handy way to override development config locally - each developer can put whatever they need in there (per-user config, developer secrets, etc.), this file is put into .gitignore
  • config/test.exs provides all necessary configuration to run tests - this is to ensure that mix test can be run right after git clone without any configuration necessary
  • config/prod.exs provides build-time config for production
  • config/releases.exs provides runtime config for production, which is essentially ENV variables mapping with System.fetch_env!/1 so the app fails to start when some configuration is missing

Config files examples

Click to expand
# config/config.exs - common build-time config for all
use Mix.Config

config :phoenix, :json_library, Jason

import_config "#{Mix.env()}.exs"
# config/dev.exs - all config for development
use Mix.Config

config :myapp, MyAppWeb.BasicAuth, user: "", pass: ""

import_config "dev.local*.exs"
# config/prod.exs - build-time config for production
use Mix.Config

config :myapp, MyAppWeb.Endpoint, server: true
# config/test.exs - all config for test
use Mix.Config

config :myapp, MyAppWeb.Endpoint, server: false
config :myapp, MyAppWeb.BasicAuth, user: "test", pass: "test"
# config/dev.local.exs - local config for development, gitignored
use Mix.Config

config :myapp, MyAppWeb.Endpoint, url: [host: "alice-dev-proxy.example.com"]
config :myapp, MyAppWeb.BasicAuth, user: "", pass: ""
# config/releases.exs - runtime config for production
import Config

config :myapp, MyAppWeb.BasicAuth,
  user: System.fetch_env!("ADMIN_USER"),
  pass: System.fetch_env!("ADMIN_PASS")

The problem

The new preferred way of runtime configuration is to use config/runtime.exs.

This file will be executed regardless if run with mix or as a part of the release.

Now, if I simply rename my config/releases.exs to config/runtime.exs it will blow up in dev & test due to System.fetch_env!/1 usage. Nobody have all the ENV values referenced locally (a lot of the are secrets).

I can’t seem to find any reference on how to deal with such case.

Any ideas?

Bonus question

Another, somehow-related issues is using .exs files as runtime configuration.

With elixir 1.10 I could add import_config "foo.exs" at the bottom of config/releases.exs and then mount foo.exs file on a production system at /app/releases/0.1.0/foo.exs (docker on kubernetes via ConfigMap).

With elixir 1.11 it now fails with ** (RuntimeError) import_config/1 is not enabled for this configuration file. Some configuration files do not allow importing other files as they are often copied to external systems, which seems to be a bit ironic, as I do want to “copy to external system” :upside_down:

The question here is: I DO want to use runtime-mounted .exs file as a configuration (alongside ENV vars) simply because it is much better than yaml, but it seems to be discouraged.

Most Liked

wojtekmach

wojtekmach

Hex Core Team

at hexpm we ended up with the following:

# config/runtime.exs
import Config

if config_env() == :prod do
  config :hexpm, ...
end

[1] hexpm/config/runtime.exs at 5b86630bccd308ecd394561225cf4ea78b008c8e · hexpm/hexpm · GitHub

Where Next?

Popular in Questions Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40082 209
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44608 311
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New

We're in Beta

About us Mission Statement