pnezis

pnezis

Elixir mono-repo best practices

We are currently in the process of restructuring our codebase. Till now we follow the monolith way (well structured though) but we have started facing scaling issues (especially on CI pipelines). Umbrella is not an option since we have multiple applications and we wish to split the configuration as well.

The main goals of this restructuring are:

  • Speed up CI pipelines - by splitting the codebase into multiple packages we can build, lint test only the affected parts of the codebase
  • Code organization and clear separation of concerns
  • Better development experience - a developer working on the API does not need to compile dozens of Broadway pipelines or LiveView applications

A Ponzo like project with path dependencies seems as the best option:

  • Maximize code resue
  • Consistent tooling, code guidelines, CI pipelines
  • No internal dependencies nightmare

On the other hand there are some caveats, the most important of which is:

  • Each project will have each own lockfile, deps and _build paths making CI configuration more complex (e.g. deps caching) and introducing incompatibilities between external dependencies

Since custom paths for lockfile, dependencies and build paths are supported for umbrella projects I was thinking the possibility of solving this issue by having a shared artifacts folder for all packages/applications ( something like rust workspaces with a common lockfile and output directory for all packages). Imagine a folder structure like the following:

project
├── .artifacts
│   ├── _build
│   └── deps
├── applications
│   ├── admin_ui
│   │   └── mix.exs
│   ├── api
│   │   └── mix.exs
│   └── data_pipelines
│       └── mix.exs
├── mix.lock
└── packages
    ├── package_a
    │   └── mix.exs
    ├── package_b
    │   └── mix.exs
    └── package_c
        └── mix.exs

Where each mix.exs will have deps_path, lockfile and build_path properly defined:

def project do
    ...
    deps_path: deps_path(),
    lockfile: lockfile_path(),
    build_path: build_path()
end
...

I have tested this on a sample project and it seems to work fine. The documentation of build_path though suggests avoiding overriding this variable:

This option is intended only for child apps within a larger umbrella application so that each child
app can use the common _build directory of the parent umbrella. In a non-umbrella context,
configuring this has undesirable side-effects (such as skipping some compiler checks) and should be avoided.

What are these side effects? Does anybody has experience with elixir mono-repos? Any advice / alarms on the aforementioned structure?

Thanks! :smiley:

Marked As Solved

Also Liked

pnezis

pnezis

Poncho is the closest to what I want to achieve, my only concern with this is the different deps and build paths per project.

What I want to achieve is something like the cargo workspaces in rust

Cargo offers a feature called workspaces that can help manage multiple related packages that are developed in tandem.
A workspace is a set of packages that share the same Cargo.lock and output directory.

pnezis

pnezis

Plain mix projects with path dependencies under a single git repo.

BradS2S

BradS2S

Agreed that diverging config by app under a umbrella project is an anti-pattern.

Functional Web Development with Elixir, OTP, and Phoenix starts by building the business logic as a separate application, without Phoenix. Might be worth thinking about breaking out your app as separate applications that are added as dependencies to the main app.

lafka

lafka

ping me once you publish something. Are you manually adding the paths between the different monorepo applications or do you have some way of discovering apps? Does your monorepo manage non-beam code as well?

pnezis

pnezis

I want to keep the code in a single repository for multiple reasons:

  • atomic commits between changes across packages
  • avoid dependencies management nightmare (we have tried the poly-repo approach with a few internal packages and this corresponds to multiple commits in different repos for a single change)
  • better visibility for the team
  • common tooling, ci rules, and coding standards for all applications
  • consistent e2e testing

Where Next?

Popular in Questions Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Phillipp
Hey, I have a NanoPi-M3 and try to install Elixir on their Ubuntu image. I followed the Raspberry Pi installation instructions from the ...
New
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement