Monorepo: The Right Fit For Your Project?
This article should help you to decide whether you go with a monorepo approach. You will find some links throughout the article which link to Nx, a great monorepo tool by nrwl, which we use a lot.
When it comes to managing software projects, there are two main approaches: monorepos and multirepos. While monorepos have gained popularity in recent years, some companies still prefer the traditional multi-repo approach. In this blog post, we'll explore the pros and cons of mono repositories, as well as the challenges associated with them. By the end of this article, you should have a better understanding of those that are a good fit for your next project.
A monorepo is a single repository that contains multiple applications, services, libraries, and tools that belong to a team or project domain. A Multirepo on the other hand separates each of those as a separate repository. In this approach, each git repository is independent and has its own version control history.
The idea behind a monorepo is to encourage collaboration and code reuse across teams. Also separating a project by concerns or creating reusable packages can be a use case. By having multiple distinct projects in a single repository, it is easier for developers to discover and leverage shared libraries based on well-defined relationships.
One of the biggest advantages of a monorepo is that it makes collaboration and code sharing easier. Since all the code is in one place, it's easy for developers to discover and leverage shared libraries. This can lead to a decrease in tech debt, as developers can reuse code instead of creating their own abstractions.
A great advantage is the possibility to do updates to several packages or projects in a single commit, allowing to integration test your changes immediately.
By having a curated set of libraries in the repository, individual teams can easily discover solutions to common problems without the need to take on the responsibility of supporting a library of their own.
A monorepo provides a better overall view of the parts of a project’s inner ecosystem. Developers can see which impact changes to their own service or library will have on other parts of the project. This can lead to better decision-making and prevent unintended consequences.
Within a monorepo, dependency management is centralised and therefore simpler to manage. This helps to prevent version conflicts across projects with the same third-party libraries and ensures that all the dependencies are up to date on the same versions.
Code reviews and tracking changes related to libraries and services across the monorepo make it easier to spot upcoming issues. Refactorings can be instantly tested across affected projects to see how they get involved. The unintended introduction of breaking changes can be detected quicker, in case unit tests are of low quality or do not cover all use cases.
On the other hand, a standardized setup with tools like EsLint, Prettier, and other code quality checks leads to consistency throughout the contained projects. This makes it easier for developers to switch between project teams or if it is necessary to consolidate projects.
One of the main disadvantages of a monorepo is that it can lead to performance issues with large projects. Checking out, building and testing a repository locally will take longer, as well as developer experience might decrease if the whole project is opened in the IDE since more files are being watched for changes and more memory is consumed. It is important to run tasks like build and test in a partial way, which is usually provided by the tools like Nx or Turborepo. Additionally, also the CI/CD pipeline will be challenged. Read our article about Monorepo CI/CD Performance to get some tips about how to improve performance.
Another disadvantage of a monorepo is that it can pose security risks when working with external contractors. Since all the code is stored in one repository, it's easier for contractors to access sensitive code they shouldn't have access to.
Finally, a monorepo can lead to limited subcultures among teams. Since all the code is in one repository, it can be difficult for teams to develop their own culture and identity.
Multi-repos put up collaboration barriers, and monorepos enforce teams to work more closely together. Conversations are encouraged and silos are brought down. This means all contributing teams should be willing to be more open and sync with other teams when necessary.
Changing a common code can impact many application components. This can make feature branch management difficult, and source conflicts can be difficult to merge. The git history is not separated per team and therefore less clear and not so easy to distinguish.
Compatibility with various development tools and services can be challenging. Some tools may not support the monorepo structure or have limitations when it comes to working with large repositories.
Another challenge with monorepos is maintaining a sense of code ownership, since teams are usually working on their specific part of a monorepo. Luckily most of the git repository platforms provide something like GitHub Codeowners to specify git change boundaries, which helps to define who should be responsible and who gets automatically assigned no Pull Requests.
If you need further boundaries to prevent ui libraries to import business logic libs or want to enforce separation by concerns, Nx's Tags can help set those project boundaries. Libraries can be tagged with multiple tags and therefore it allows shared libraries to be used throughout all projects.
Here at Satellytes, we are working a lot with monorepos. Our main experiences come from using them in the context of Angular and React frontend applications, as well as building shared UI libraries, that are used by a broader user group. We also help customers shape their best developer experience.
In general, we find monorepos a good fit in a setup with a common technology stack, and where teams are tightly connected and therefore easier to be aligned.
We have built a consistent developer experience across multiple distinct departments, distributed in various countries across the globe. We wanted to reach a state of "all developers of our companies should use one UI library, framework, and general blueprint". This is a bit more challenging but still, it is beneficial to work in a monorepo.
What we have learned is that in this case, having a dedicated team has benefits. This includes onboarding new teams, alignment, harmonization of shared elements, contribution documentation, and tasks like repository housekeeping (dependencies, tooling, pipelines, cleanup).
One often-mentioned downside of monorepos is the assumption, that release tools like standard-version can only have one version across all libraries. This is true for the default setup (VERSION file in the root) since the tools are built to target a single package. But it is quite simply to extend by (in case of standard-version) to define a .versionrc.js
per library and run npm run publish
in each of the library folders.
Choosing the right tool for managing a monorepo is also crucial, one that we can totally recommend is Nx by nrwl.io. We experienced it as working very well for all our Angular and React projects. If our word is not enough, you can check monorepo.tools for a great overview of the currently most used monorepo management tools.
Further, the pipeline performance issues can be taken care of, check out our blog article about Maximimizing CI/CD Performance with Nx Workspace, which also contains general tips in case you are not going with Nx.
Mostly git
works very well with very large repositories and millions of lines of code. If you reach more than that and experience degraded performance, git sparse checkout
can help lower the footprint. If you have serious performance issues with Git commands like status and fetch, you can try Microsoft's git distribution, which is designed to support highly large-scale monorepo scenarios with thousands of projects in one repository.
Ultimately, the decision between a monorepo and a multi-repo approach comes down to your project's and organization's specific needs and requirements. If you value collaboration and code sharing, a monorepo may be the best choice for your project. If you prefer less tooling overhead, faster build pipelines, then the multi-repo approach might be a better fit for you.
If you're still unsure which approach is right for your project, consider consulting with experienced software developers or members of your team. They can provide valuable insights and guidance based on their experiences and expertise in the field.