I should elaborate here. If you allow the user to pass arguments through child_spec then the user is really free to start as many processes as they want. Using Redix as an example, the user is free to do this:
def start(_type, _args) do
children = [
{Redix, name: :primary},
{Redix, name: :secondary},
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
Its common for people to use config.exs for this but its not necessary to do so. You can just as easily do something like this:
def start(_type, _args) do
children = [
{MyClient1, adapter: adapter()},
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
def adapter do
if System.get_env("MIX_ENV") == "prod" do
DBAdapter
else
Sandbox
end
end
In most of our apps we use vapor for reading environment config but it boils down to the same thing. If you don’t want to pass the adapter module as args you could just as easily use Application.put_env to store the correct adapter to use.
The reason that ecto needs the adapter specified in config.exs (at least historically) is because its using macros to inject the correct functions into your Repo module. Personally I don’t think the pattern that Ecto.Repo or Phoenix.Endpoint use should be emulated without a very compelling reason.
FWIW the elixir library guidelines have some points on this as well.






















