Mono Repository
Overview
A Monorepository is an architectural concept, which basically contains all the meaning in its title. Instead of managing multiple repositories, you keep all your isolated code parts inside one repository. Keep in mind the word isolated—it means that monorepo has nothing in common with monolithic apps. You can keep many kinds of logical apps inside one repo; for example, a website and its iOS app.
To make this happen, you will probably want to isolate large features into some packages and then use them via a single entry point in your main app. But how do you manage those packages? Each package will have to have its own workflow environment configuration, and this means that every time you want to create a new package, you will have to configure a new environment, copy over all configuration files, and so on. Or, for example, if you have to change something in your build system, you will have to go over each repo, do a commit, create a pull request, and wait for each build, which slows you down a lot. At this step, we are meeting the monorepos.
Instead of having a lot of repositories with their own configs, we will have only one source of truth—the monorepo: one test suite runner, one Docker configuration file, and one configuration for Webpack. And you still have scalability, opportunity to separate concerns, code sharing with common packages, and a lot of other pros. Sounds nice, right? Well, it is. But there are some drawbacks as well. Let’s take a close look at the exact pros and cons of using the monorepo in the wild.
Monorepo Advantages
-
One place to store all configs and tests
- Since everything is located inside one repo, you can configure your CI/CD and bundler once and then just re-use configs to build all packages before publishing them to remote. Same goes for unit, e2e, and integration tests—your CI will be able to launch all tests without having to deal with additional configuration.
-
Easily refactor global features with atomic commits
- Instead of doing a pull request for each repo, figuring out in which order to build your changes, you just need to make an atomic pull request which will contain all commits related to the feature that you are working against.
-
Simplified package publishing
- If you plan to implement a new feature inside a package that is dependent on another package with shared code, you can do it with a single command. It is a function that needs some additional configurations, which will be later discussed in a tooling review part of this article. Currently, there is a rich selection of tools, including Lerna, Yarn Workspaces, and Bazel.
-
Easier dependency management
- Only one package.json. No need to re-install dependencies in each repo whenever you want to update your dependencies.
-
Re-use code with shared packages while still keeping them isolated
- Monorepo allows you to reuse your packages from other packages while keeping them isolated from one another. You can use a reference to the remote package and consume them via a single entry point. To use the local version, you are able to use local symlinks. This feature can be implemented via bash scripts or by introducing some additional tools like Lerna or Yarn.
Monorepo Disadvantages
-
No way to restrict access only to some parts of the app
- Unfortunately, you can’t share only the part of your monorepo—you will have to give access to the whole codebase, which might lead to some security issues.
-
Poor Git performance when working on large-scale projects
- This issue starts to appear only on huge applications with more than a million commits and hundreds of devs doing their work simultaneously every day over the same repo. This becomes especially troublesome as Git uses a directed acyclic graph (DAG) to represent the history of a project. With a large number of commits, any command that walks the graph could become slow as the history deepens. Performance slows down as well because of the number of refs (i.e., branches or tags, solvable by removing refs you don’t need anymore) and amount of files tracked (as well as their weight, even though heavy files issue can be resolved using Git LFS).
Resources
In-favor
- https://www.toptal.com/front-end/guide-to-monorepos
- https://www.atlassian.com/git/tutorials/monorepos
- https://nx.dev/
- https://medium.com/@tytusplanck/scaling-our-largest-angular-platform-with-nx-8aa70ee3619f
- https://www.perforce.com/blog/vcs/what-monorepo#:~:text=A%20monorepo%20(mono%20repository)%20is,it%20easier%20to%20refactor%20code.