<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 "> Bitovi Blog - UX and UI design, JavaScript and Frontend development
Loading

Angular |

The Case for Monorepos: How to Develop with Monorepos

Should you be using a Monorepo? Monorepos are great for projects with multiple technologies & platforms. Read this post to learn how to use Monorepos!

Ilyass Elfouih

Ilyass Elfouih

Twitter Reddit

Monorepos are hot right now, and not for the wrong reasons. This blog will try to demystify the trend of grouping all your applications and libraries into one single repository and see why using a Monorepo in your next project is worth consideration.

To illustrate the use of Monorepos, we will use the example of a restaurant application.

Let’s imagine you are the owner of a restaurant called Happy Restaurant, and you want to have an application that handles the following:

  • Customers can order from the Menu and check the status of the order.
  • Chefs can receive and update the preparation order status.
  • Carriers can receive and update the delivery order status.
  • The administrator can edit the Menu.

Monorepos in a Nutshell

Monorepo is a single version control repository such as git that contains multiple and distinct projects that can be deployed independently.

Hearing this for the first time sounds unusual; you may think something like: you can’t group all your projects in one git repo and expect everything to work.

You are right! You can’t, not without the proper tooling in place and a well-defined relationship between your projects.
We will take a quick look at Monorepo tools and best practices in this post

Differences Between Monorepos, Polyrepos, and Monolith

Polyrepos

Polyrepos or Multirepos are the opposite of Monorepos. Multiple distinct projects in different “git” repositories is considered a Polyrepo.
Contrarily, in a Monorepo, we have all our applications in the same “git” repository, and they can be deployed separately.
Using a Monorepo in our Happy Restaurant project means having four separate frontend applications and one backend application, broken down into the following structure:

  • Admin
  • Carrier
  • Order
  • Prepare-order
  • API

One might wonder, why not group all these applications into one project and save the trouble?
You CAN do that, and by doing so will be creating a Monolith application. And this exact development strategy is a common misconception about a Monorepo application.

Monolith

With a Monolith application, you can use only one technology, platform, and deploy artifacts.
The four frontend and backend applications in our Happy Restaurant project will have the same framework and language. And they need to be deployed to the same platform; web, for example.
On the other hand, with a Monorepo, we can have applications with different technologies and platforms that can be deployed independently. For instance, our admin application could be an Angular application deployed on the web, and our order application could be an Ionic application deployed to Android and ios stores.

Benefits of Using a Monorepo

1. Code Sharing

One of Monorepo’s strengths is sharing code between applications and libraries. For example, suppose the design team decides to have a standardized primary button in all our applications. In that case, you will need to create a library that will encapsulate all the UI and logic for your Button, then import it into your applications.

monorepos-1

With this in place, it’s also simpler to refactor your shared-btn and update all your applications in one single commit.
One thing to note is that you do not need to publish the shared-btn library to a registry; you can consume your library internally between your applications and other libraries.
Using TypeScript aliases and Angular, you will be importing your library as follows:

// login.module of Order application 

import { SharedBtn } from "@shared/button";

@NgModule({
  import:[SharedBtn],
  ....
}) 
Class LoginModule{}

Then use your shared-btn in your template:

// login.component.html

<form>
  <input type="email">
  <input type="text">
  
  <shared-btn></shared-btn>
</form>

2. Consistency in Your Applications

Switching to Monorepos significantly impacts maintaining a consistent code style and linting rules across all your applications and libraries.

Let’s say your team decided to use single quotes instead of double quotes.
With a Multirepo structure, you will update all your repositories with the new rule. On the other hand, with a Monorepo structure, you will be updating this rule only once, and all your applications and libraries will benefit from the new update.

3. Visibility

With a Monorepo structure, you can have up-to-date visibility on all your applications and libraries.
By visibility, we mean you can see the available applications and libraries in one place at any given time of your project lifecycle without jumping between repositories.

And suppose you are using a tool like Nx for managing your Monorepo. In that case, you have access to an excellent command that generates a dependency graph of all your applications and libraries.

Run:

$ npx nx dep-graph

Result:

monorepos-2

 

There is no need for you to keep documentation of relationships between your applications and libraries.
In addition, the onboarding of new hires is less time-consuming; they can quickly figure out the relationships and get familiar with the project.

4. Collaboration

Working with a Monorepo simplifies collaboration between teams inside the project.

For instance, it’s easier to read others’ code for inspiration on how to implement a feature or fix a bug.

You can also work on PR with backend and frontend, then merge your changes into a single commit.

Coupling frontend and backend in one commit might sound scary because, if you ever have a backend issue, for example, and you want to roll back to the stable version, the frontend will roll back too (because we have a single commit strategy).

To fix the backend issues and keep the latest stable frontend version, you will need another git branching work and a redeploy.

So if you prefer shipping code faster using single commits and you can handle the coupling issues, Monorepo is your friend.

Challenges

  • Read rights: If your company does not want all developers to have read access to all source code, unfortunately, Monorepos will not help you in this context. (For now, at least).
    Because the problem here is on the versioning control side, If you are using git, you can’t clone only one section of your source code.

    To fix the read rights to everyone issue, you can, for example, extract the confidential part of your project into another repository and then try to publish to some registry the shared source code between the extracted repository and your Monorepo.
    Using our example, we can do that if we have some backend secrets and want to keep them in a separate repository. We will need to version and publish the shared models, interfaces, DTOs… to a registry, then consume them in our backend.

  • Build time: For enormous applications using Monorepo (more than 100 applications and libraries), you will notice slowness in build time and dependency installation. The slower build time is because, in your Monorepo, you will be architecting your project in a way that allows you to share code between your libraries and applications, which may sometimes result in building unnecessary applications and libraries.

    However, you can solve this slowness with a tooling system that tries to build only the affected applications and libraries.

    For example, when using Nx, you will be running the following command:

    $ nx affected:build --base= origin/main --head=$PR_BRANCH_NAME # where PR_BRANCH_NAME is defined by your CI system

     

  • Learning curve: You will need to learn more about the tooling available and how to work with it. Sometimes, you will also need to know more about new architecture patterns like DDD or Micro frontends. Here is a good starting point to learn about Micro Frontends and Module Federation.

Tools to Help Manage Monorepos:

To manage your Monorepo, you will need the proper tools for your use case. The available ones are :

  • Bazel (by Google): “A fast, scalable, multi-language and extensible build system.”
  • Gradle (by Gradle, Inc): “A fast, flexible polyglot build system designed for multi-project builds.”
  • Lage (by Microsoft): “Task runner in JavaScript mono repo.”
  • Lerna (by Nrwl): “A tool for managing JavaScript projects with multiple packages.”
  • Nx (by Nrwl): “Next generation build system with first-class Monorepo support and powerful integrations.”
  • Pants (by Pants Build): “A fast, scalable, user-friendly build system for codebases of all sizes.”
  • Rush (by Microsoft): “Geared for large mono repo with lots of teams and projects. Part of the Rush Stack family of projects.”
  • Turborepo (by Vercel): “The high-performance build system for JavaScript & TypeScript codebases.”

For a more detailed benchmark of each tool’s features, check this awesome one initiated by the NX team.

Conclusion

Using a Monorepo can be an excellent solution for projects with multiple technologies, production platforms, and teams. Monorepos are also helpful for everyone who wants to enhance collaboration.
However, it’s a technology that should be consumed with caution and not blindly adopted.

Like any other software engineering topic, there is no one-size-fits-all. Your job as an Angular developer is to know each technology’s pros and cons and ensure it fits within your project constraints.

monorepos-3

If you need help figuring out what those constraints are or how to think about them, our team of Angular experts can help. We’ve worked with projects of all sizes and can help yours succeed, too. Schedule your free consultation!