Monorepo vs Multi-repo vs Monolith

Magenta Qin
4 min readFeb 11, 2023

--

This blog compares advantages and disadvantages of mono repo, multi repo and monolith architecture, and discuss which architecture to choose in real life.

Monolithic Architecture

A monolithic architecture exists at the very early stage of your project. It has two main features:

  • One code base: it is managed by only one git repo.
  • Coupled: all features, utils and services are coupled.

The project directory may look like this:

├── assets
├── components
│ ├── Button.js
│ ├── Modal.js
│ └── ...
├── node_modules
├── pages
│ ├── Payment
│ │ └── ...
│ │ └── ...
│ ├── Shoping Cart
│ │ └── ...
│ │ └── ...
│ ├── Inventory
│ │ └── ...
├── utils
├── package.json
├── webpack.config.js
├── yarn.lock
└── README.md

Advantages

Due to the simplicity of one code base, it makes us easy to develop, deploy, test and debug.

Disadvantages

Disadvantages appear as the application grows bigger and bigger.

First, slower development and deployment. Making a small change requires compiling, deploying and testing the entire platform, which would greatly slow down the speed of development and deployment.

Second, low reliability. A small error could shut the entire application’s down.

Third, low scalability. All of the components, functions, services and utils are coupled together, which makes it difficult to scale individual parts.

Fourth, low flexibility. Although the project is maintained by many teams, they have to stay in the same tech stack.

Multi Repo Architecture

How about splitting payment, shopping cart and inventory into three separate repos?

This is what we call: multi repo architecture.

// Repo1: Payment
├── assets
├── components
│ ├── PaymentButton.js
├── node_modules
├── pages
│ ├── main.js
├── package.json
├── webpack.config.js
├── yarn.lock
└── README.md

// Repo2: Shopping Cart
├── assets
├── components
│ ├── ShoppingCart.js
├── node_modules
├── pages
│ ├── main.js
├── package.json
├── webpack.config.js
├── yarn.lock
└── README.md

// Repo2: Inventory
├── assets
├── components
│ ├── InventoryComponent.js
├── node_modules
├── pages
│ ├── main.js
├── package.json
├── webpack.config.js
├── yarn.lock
└── README.md

It does solve the problems of monolithic architecture. However, it brings other problems.

The biggest problem is: hard to share resources(components, configs, utils and test suites).

Maybe you could use git submodule or npm packages to encapsulate these common resources, but it will make the project more complicated and hard to manage.

Update process is too tedious. You have to publish the utils repo, component repo and test suites repo separately,and manually manage the versions of these dependencies.

Even worse, when you want to roll back in production mode, you have to roll back these repos separately.

Monorepo Architecture

Simply put, mono repo architecture enables you to manage multiple projects within one code base.

In this example, there are 6 packages: utils, components, services, payment, shopping-cart and inventory. Each package has its own package.json and manage its dependencies by itself.

├── packages
│ ├── utils
│ │ ├── package.json
│ ├── components
│ │ ├── src
│ │ ├── package.json
│ ├── services
│ │ ├── package.json
│ └── ...
│ ├── payment
│ │ ├── components
│ │ ├── pages
│ │ └── package.json
│ │ └── node_modules
│ │ └── webpack.config.js
│ │ └── tsconfig.json
│ │ └── README.md
│ ├── shopping-cart
│ │ ├── components
│ │ ├── pages
│ │ └── package.json
│ │ └── node_modules
│ │ └── webpack.config.js
│ │ └── tsconfig.json
│ │ └── README.md
│ ├── inventory
│ │ ├── components
│ │ ├── pages
│ │ └── package.json
│ │ └── node_modules
│ │ └── webpack.config.js
│ │ └── tsconfig.json
│ │ └── README.md
├── node_modules
├── package.json
└── README.md

Advantages

1/ Easy to share resources and manage dependencies. You can directly use tools like Lerna to help you manage package versions.

2/ Common dependencies can be installed in the root directory, and package itself does not need to install it again, which saves installation time.

3/ Independent and flexible: Package itself can have its own dependencies as well as shared dependencies. It’s easy to scale each package.

Disadvantages

1/ Slow git pull. Git repo grows bigger and bigger. Although you want to pull the code of your own package, you have to pull other’s code as well.

2/ Deploy coupled. You have to deploy all of the packages together even if you only update one package. Tools like Lerna could help you auto detect which packages are changed, and only deploy those packages.

3/ Hard to grant limited granular git access. As all code lies in one repo, the git access is bound together. It seems impossible to grant git access to only one package.

Common Monorepo solutions are Pnpm, lerna and Nx. Details of them will be illustrated in later blogs.

Conclusion

The comparison among those three architecture is shown below.

In our practice, we combined those three architecture together.

Each project repo is a monolithic architecture.

We put independent projects in multi repos, like independent frontend and backend projects under different business lines.

But for the shared independencies, like utils, components, configs, services, we organize them in one mono repo.

Only core members have access to the mono repo. Developers only have their own project git access. This could greatly avoid the disadvantages of mono repo.

References:

--

--