Dependecies in umbrella projects

Background

I have an umbrella project with several apps inside. Now, some of these apps have some dependencies in common, for example, lets say they all use the library A.

Problem

Since umbrellas have their own mix.exs file, I thought this would be a perfect place to put all the dependencies all the apps share.

However if I do that, when I enter the individual apps and try to compile them I can’t, because the dependencies are not there.

For me this is confusing because now I need to copy paste the dependency of library A in all my apps, and if they have different versions the whole thing will explode into horrible pain (which I want to avoid).

Question

What is the purpose of the mix.exs file that is in the umbrella app?

It’s most useful for dependencies bringing in mix tasks or other development tooling your apps don’t directly depend on.

1 Like

Could you give an example of such tooling? Would the following belong inside this category?

  • excoveralls
  • exdocs
  • escript

At least the first two can belong there, yes. Not sure what escript does.

escript allows you to create executable terminal applications (like a bash file) with elixir.

It is especially useful for scenarios where you don’t need to have an application running 24/24 hours a day (like a webserver) and instead need something to run as a one off command every once in a while.

Here is more information about escript if you find it interesting:

It’s an imperfect analogy but it’s useful to think of an umbrella as a monorepo, because you can assemble a release that only has one or a few of the umbrella children included. It’s a natively supported concept. In order for that to hold true, each umbrella child need to comprehensively list its runtime and compile-time dependencies in its own mix.exs file to be semantically correct, or you might produce non-viable releases for that subset of the umbrella.

If you only ever run/test/release from the root of the umbrella you’ll eventually find that you’ve been shadowing important concerns. If you never ever intend to deploy the components in a modular way, I’d posit that your umbrella structure is largely ceremonial and producing low to no value as an architectural choice.

With the exception of in_umbrella deps and some relative paths in mix.exs I highly highly encourage writing your umbrella apps with zero awareness that they are in fact a member of an umbrella. You’ll have better chances of success at runtime/deploy time and cleaner boundaries between the siblings. Elixir 1.11 will bring some small benefits with regards to circular dependencies and ignoring those boundaries.

2 Likes