What’s wrong with Umbrella Apps?

I have this non-umbrella app with two Phoenix endpoints, “api” and “web”: lib · trunk · Mikko Ahlroth / minisome · GitLab – And it really wasn’t any hassle at all. They’re both completely separate, yet in the same project. Now only one of them has frontend stuff, so setting up esbuild/webpack for two endpoints would have to be a custom job, but the Elixir side was easy to have separately.


A few months ago I started consulting on an umbrella project (about 10 apps). The first thing I did was deumbrellization of the project, which brought some benefits:

  • about 2k LOC less, due to removal of the repetitive boilerplate across subprojects
  • faster test and build times
  • simplified folder structure
  • better tooling support for simple projects

As an example of the last point, various paths that are printed by mix tasks (e.g. test IIRC) aren’t “clickable” in vscode (I couldn’t click to open the file in the editor), because the printed paths are missing the apps/myapp/ prefix. I found this extremely annoying and disruptive. This alone is for me the reason to avoid umbrella as much as possible.

Generally, my sentiment is that if the subapps are not deployed separately, the umbrella app doesn’t bring anything useful to the table, compared to single project + boundary. Even if boundary is not used, I find the benefits of umbrella don’t justify the issues mentioned above.


Thank you for sharing your settings. I will probably steal some ideas from it for my future projects. ^^

My concern is that if I use customized folder structure within a Phoenix app, I couldn’t take full adavantage of Phoenix generator anymore. The generators I think expect a given structure.
For example I don’t know how I can tell mix phx.gen.html to put generated controller-view-templates files sometimes in admin_ui folder and the other times in the default_ui folder.

Another concern is for example I would like to have different priv folder per UI for gettext translations instead of using a single folder with domain translations. Consider that my UIs don’t support the same set of locales and have their own domains of translation as well.

If there are a number of generators that don’t support umbrella project, I also feel like many can work out of the box without even being aware that the project is an umbrella. After all an umbrella app is just an app like another one in the first place.

I think it is a mater of preference but I’m really happy with umbrella as long as I keep the number of apps small and of course make sure all my apps depend only on the core app.


Thanks everyone for the discussion and sharing experiences. As I say, all the large projects I’ve worked on have been flat and have only experienced umbrellas on small (mostly personal) projects.

Much food for thought. I think the most significant issue with umbrellas reported here is around tooling, which is also an issue that I’ve also encountered. (There’s also that example and tutorials are written for flat structures and need to be tweaked for umbrellas). I really get how that could be a deal breaker.

I’m also inspired to take another look at boundary, which looks pretty useful. (I think the last time I looked at it things were in a very early state and I didn’t get round to investigating it further).

I’m curious about how much faster.


I wonder why you did not report a bug (or why it was closed when you did) as this simply seems like a bug to me.

I don’t have the numbers anymore, but the difference was visible. IIRC, the main reason was that various mix tasks (e.g. compile, test) processed apps sequentially. OTOH, when everything is in the same project, compilation of modules and tests can run concurrently on the entire codebase.

Whether that’s a bug is debatable, and I’m also unsure where should this be tackled (in the editor or in mix). Coupled with the fact that I personally don’t find umbrellas particularly useful, I didn’t spend any additional time on this. Instead I focused my effort on removing the umbrella, which brought various other benefits, as I mentioned earlier :slight_smile:


I remember this definitely being an issue. I’ve just tried it out as I happened to be picking up an old project again, and the cmd-click now works from the root of the umbrella. ¯\(ツ)/¯ so I think it’s something that’s somehow got fixed in VSCode (or Elixir LS).

Our xrefs sections became huge, so we had to ask why??

We used umbrella apps to determine what should be started as a part of Kubernetes deployments. But then I collapsed the umbrella app into a single app and used environment variables to determine what processes should be started. It was much more simple and we didn’t have all those dependencies (xref) problems.

Umbrellas can’t separate out your mix deps anyway… so they really just become about making separate releases. But disk space is cheap these days… why not have a single release and use env vars to determine what’s started?

1 Like

That was my original sentiment as well, but it’s very easy to conditionally start processes based on env vars (inspired by how Phoenix conditionally starts its endpoint).

Our monolithic Elixir app is responsible for over a dozen different Kubernetes deployments, all just using env vars to determine what processes are started.


After thinking more about this I realise that I could use multiple gettext backend modules in the same app and define different locations for their priv folder.:sweat_smile:

# Look for translations in my_app/admin_ui/priv/gettext instead of
# my_app/priv/gettext
use Gettext, otp_app: :my_app, priv: "admin_ui/priv/gettext"

I knew it is possible to define the location for the translations files but I didn’t think I can just define multiple modules such as MyAppWebGettext, MyAppAdminUiGettext etc.

I guess I could think of a way to have also different locations for assets.

And after reading all the posts in this thread, I guess I can be happier without my umbrella setup. Let’s embrace simplicity. ^^


For generators such as phx.gen.html I would maybe create a sample project with the good namespace and generate the files inside that project, then I would copy and paste them in the desired folders of the project that I customized the folder structure.

Definitely I will give a try to thoses ideas in my next project to see how easier the things would become.

Yes, I also prefer this over umbrellas, and it’s the approach I advised to the clients in the past in the same scenario (microservices on k8s).

1 Like

There’s downsides to that as well though, as (only) runtime conditional starting of things still means you ship all the code everywhere. That might be a tradeoff, which can be made or might not. But which applications are put into releases can be customized in plain mix apps just as much as that can be done for umbrellas.

I think umbrella projects are not popular because very few people understand what they are, how to use them and why use them.

On top of that, there multiple issues mentioned here and elsewhere about troubles with tools, dependencies, testing etc.

Official docs just tell you to create an umbrella project without telling you any of the reasons why. (Well, some description it’s tacked to the end of the previous section, “Internal dependencies”).

So, back to your question:

What issues have people had that has put them off Umbrella Projects?

Most people never even started with umbrella projects because they are an unknown.

1 Like

Hi all,

Thanks again for this discussion. I thought it might be worth writing up my conclusions (which may not be the same as your conclusions).


Fascinating. Great writeup!

I also like umbrella projects, and have used it for nearly all production projects. My working environment is startups with very rapid prototyping. I haven’t had issues with keeping the projects DRY and the projects have always felt fast to build and deploy.

This is one example of an umbrella structure based on real world umbrella projects I’ve helped build:

  • Ecto app
    • This is the meaty main app containing all business logic
  • Phoenix app for API
    • Handling the API communication over HTTP/WebSockets and manages sessions
  • Phoenix app for landing pages
  • Phoenix app for internal admin
  • Plug app acting as reverse proxy
    • Infrastructure required traffic had to be served on a single port in the docker container
    • Also handles requests to non-elixir web apps running in the container

The reason I always went with umbrella was that it seemed to give me the best balance between monolith and microservices. It helped me abstracting interfaces and concerns in a way that felt very natural and easy to understand.

I’ve actually went the other way of what @sasajuric described. I used umbrella structure to help clean up a messy Phoenix app. It helped remove odd code paths, clean up dependencies, and assets.

Also very recently showcasing the umbrella structure helped me convince a microservice heavy (AWS lambda) team to give Elixir a try and to keep it monolithic for faster development :smile:

The comments here are thought provoking. Thanks for initiating this discussion @paulanthonywilson! I’ll have to try some different approaches as well.


A better solution is to just be unafraid to make top level namespaces in the main app (like how Phoenix creates MyApp and MyAppWeb)

That was a game changer for me.

Also realizing that my team doesn’t want true microservices. We simply want individually scalable deployments, but on a shared codebase.


Yep, this is like the ideal use for them in my opinion. Good for code/config re-use between strongly related projects that have more than one deployable build target, and different resource/scaling needs.

Precisely this!

There’s the further issue that you also have to conditionally configure other dependencies, like Ecto pool sizes, depending on the target environment. This is something you could get clever with using Mix.target for, but it still permutes your config access at every point it is used.


I was trying to remember why I used to get frustrated working on one app I had, that was an umbrella app.

More directories can be a pain to navigate, especially if you are using a navigation tree. Having to be in different directories perform different mix tasks can also be a bit of a headache.

This was why. I was working on was a web application, that had one app for the Ecto/context layer and one for the Phoenix/GraphQL API - and it drove me nuts needing to constantly swap between folders to run different mix tasks.


it drove me nuts needing to constantly swap between folders to run different mix tasks

Unless it’s a one-off, I’m always using mix aliases at root with mix cmd to target apps:

  "my_task": "cmd --app app_1 mix my_task"

Interresting. Another solution is to have multiple tabs opened in the terminal and just have each of them pointed to the folder of a different app of the umbrella project.

I do similar setup for my code editor. Multiple workspaces for the same umbrella project. Depending on which app I want to work on, I just switch between the workspaces.