Global Configuration in an Umbrella App

I’m wondering what best-practices are for sharing configuration options between multiple applications under an umbrella app. However, I feel like this risks the modular independency and can make apps dangerously dependent on one another.

Option 1:
Create a “helper” app inside the umbrella for “business-wide” code (e.g. mix tasks) that could also provide a namespace for “global” config options such as the number of results returned per page in a paginated result set. In our umbrella’s config, we could reference config values using our helper app’s namespace:

config :helper, per_page: 20

And reference it in our other apps, e.g.

Application.get_env(:helper, :per_page)

Option 2:
Use environment variables.

Does anyone see any advantage one way or the other? Or are we looking at this the wrong way? Any input appreciated!

2 Likes

I would recommend against having an app in the umbrella be responsible for all of the umbrella’s configuration because this functionality is already possible through the config files at the top level of the umbrella.

The two options you describe could be used in conjunction with each other, meaning a config variable can reference an environment variable and provide it to each app.

The difference is whether you want some variables to live in code or to live in the environment.

I’m currently thinking to go with the helper application. I don’t think it’s a bad thing. If I’m working in a team or even from more than one PC, it makes sens not to force every one to define a bunch of environment variables that have nothing to keep secret (or be forced to redefine them when I’m using a different PC).

Naively I first tought that I could just define a config within a non existing application key like:

config :global, blog_url: "some_url"

It works fine in dev environment but when I build a release of my umbrella project and tried to start it I got the error:

** (exit) an exception was raised:
** (ArgumentError) could not fetch application environment :blog_url for application :global because the application was not loaded/started. If your application depends on :global at runtime, make sure to load/start it or list it under :extra_applications in your mix.exs file

Then googlging on how to handle global configuration in Umbrella leaded me here.

Maybe if one has already a child application in the Umbrella project such as :core on which all the others depend, then one could just use that app for the purpose…

Imo the simplest solution would be something like this:

for app <- [:myapp, :otherapp] do
  config app, blog_url: "some_url"
end

Shared config just means config happens to be the same for multiple applications. If there’s actual business logic attached to configuration I’d consider another application, which each app depends on.

1 Like

In general I have one “root” application that is the essence of the everything else and “satellites” applications (like web UI, API, and whatever else there is). Even if the logic of the application is splitted between different applications, then there is single “root”. I store such configuration in that root and then I expose it via functions in the “root” module (in general named after application itself) of “root” application.

2 Likes