Splitting Phoenix monolith into umbrella apps

Almas Akchabayev
2 min readJan 31, 2017

Motivation

On the latest Elixir project, we wanted to leverage umbrella structure and build reusable apps. We wanted phoenix app to just be a gateway for other apps and have no other responsibilities. We thought that it would dramatically reduce complexity, scaling capabilities and working in teams. And we were right! It is very convenient way to structure backends. Just below you can have an “eagle eye” view on the setup.

apps/account <- Ecto models, DB manipulationapps/auth <- authentication apiapps/web <- channels, controllers, router (no models)

In this post I will walk you through the minimal setup.

Creating Project

So let’s CREATE an umbrella project

$ mix new phoenixella --umbrella
$ cd phoenixella/apps
$ mix phoenix.new phx --no-ecto --module Phoenixella.Phx

We will not have any models in our phxapp, so we use — no-ecto option.

To tidy things up CHANGE elixir version to 1.4 in project/0

Also CHANGE application/0 to

  def application do
# Specify extra applications you'll use from Erlang/Elixir
[extra_applications: [:logger],
mod: {Phoenixella.Phx, []}]
end

to get advantage of application inference introduced in Elixir 1.4.

Interacting with other apps

I am going to write up a tutorial, where we are going to use this structure. However the overall concept is quite simple.

For instance in an OLD way (phoenix monolith) we would write something like this:

In phoenixella/apps/phx/web/models/user.ex

defmodule Phx.User do
schema "..." do
...
end
end

And in phoenixella/apps/phx/web/controllers/user_controller.ex

Repo.insert! %User{}

In a NEW way we would write it like this

In phoenixella/apps/account/lib/user.ex (Notice here that we are in a different app called “account”)

defmodule Account.User do
schema "..." do
...
end
end

In phoenixella/apps/account/account.ex

defmodule Account do
alias Account.User
def create_user(params) do
%User{}
|> Repo.insert!
end
end

And in phoenixella/apps/phx/web/controllers/user_controller.ex

case Account.create_user(params) do
{:ok, user} -> render ...
{:error, changeset} -> render ...
end

Thanks for reading this through. It is my first ever blog post, so if you have questions or suggestion don’t hesitate and comment!

--

--