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

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> somethi...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Other popular topics 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
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
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

We're in Beta

About us Mission Statement