Splitting application at runtime

I have an app that performs several functions inside a single application.

  • Phoenix WebServer/Api
  • GRPC Server
  • Backend Processing

I would like to keep the app as a monolith instead of breaking apart into different ‘services’. Is there an idiomatic way to startup certain portions of the app at runtime. Perhaps I could have an environment var that controls what component/services should be started.

Is this just a matter of setting up the supervision tree of the app to control what services start? I have briefly looked at Umbrella apps, but not sure they would really fit my use-case

Currently I am tinkering with the children of the application to control what apps get started. Not sure this feels right.

use Application

  def start(_type, _args) do
    children = children(Mix.env)

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Cogito.Supervisor]
    Supervisor.start_link(children, opts)

  defp children(:test) do
    children(:default) ++ [


  # Other configurations...

Yeah, that’s quite fine, people do it all the time:

def start(_type, _args) do
  children = x_app() ++ y_app() + z_app()

def x_app() do
  if System.fetch_env!("X_ENABLED") == "1", do: [AppX], else: []

# similar for apps Y and Z