Library configuration - multi-instance

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.