The monorepo pattern uses a single version control repository for all your projects and assets. You merge your server, frontend, and infrastructure configuration files into one repository that everyone contributes to. Should you use it?
The pattern is popular with large tech companies. Google, Microsoft and Facebook are among the organizations that use monorepos. What makes a monorepo so attractive?
Monorepo is opposed to multi-repo. The multi-repo pattern creates a new repository for each of your projects. It̵
When you build an app, you may have three repositories:
- Server side code: Your API (possibly with additional repositories for database schema and documentation).
- Android project: The Android build of your app, with Java or Kotlin.
- iOS project: Objective-C or Swift for your iOS app.
Here everything that makes up your business is broken down into different functional units. With a monorepo, you leave that grouping and always take the aggregated view. All your assets belong together and are versioned accordingly.
One of the most frequently mentioned advantages of monorepo is collaboration. In a monorepo, everyone sees everything. This provides clarity, promotes openness and makes it easier for people in different teams to access each other’s work.
People can more easily collaborate on a task, even if it falls outside their usual responsibilities. In a multiple repos scenario, you may need to request access to the relevant repository first. This adds friction that completely avoids the monorepo approach.
Monorepos encourage everyone to take ownership of the end goal rather than the individual parts that make up it. This can lead to people feeling more involved and better informed about what is going on. An app developer may never touch the server components, but they can “feel” them along with their own work.
Ease of abstraction
Monorepos also simplify code abstraction. It is common to get similar functionality in your backend and frontend components. It makes sense to summarize this in a shared library.
In the multi-repo paradigm, you have to create a new repository and reference it in the other. That can be by building a package or by using Git submodules. Either way, a lot of work is needed before your abstracted code can be traced back to the projects it came from.
The process is easier if you have a mono repo. You can move the code to a logical folder and then import it wherever you want. An “abstraction” takes a matter of seconds. There’s the same convenience when it comes time to document the code: you can add the documents to your shared documentation system.
Multi-repos also present practical barriers to code abstraction. A development team member often does not have the necessary GitLab, GitHub, or Bitbucket permissions to create a new repository. This results in even greater overhead when a team leader needs to approve the new library and set up a repository. Monorepos helps individual developers create reusable code by eliminating special abstraction processes.
further than to create the abstraction, monorepos simplify the maintenance of shared modules. You don’t have to update every consumer of a package every time you update it. All dependencies exist in the same codebase, so you can reference them without a package manager or special version control.
Using a monorepo can speed up the development speed. We’ve touched on this in the previous sections, but it’s worth paying more attention to here.
Monorepos reduce duplicate actions. If you need to refactor, it’s a single Find and Replace to apply the change to the entire codebase. Less toggling between projects and fewer pull requests to review.
Contributors get more opportunities to serve themselves. Because information isn’t stored in team repositories, people are better equipped to search for the details they need. This can reduce the back and forth during code planning and review.
These features also help to restructure an existing system. Trying to split an outdated application into its “frontend” and “backend” may be the wrong approach. Changes on one side will inevitably affect the other, so you’ll be constantly reconciling the two repositories. Using a monorepo helps you quickly refactor large chunks of codebase knowing you’re affecting the entire system rather than patchy components.
Who are Monorepos intended for?
Monorepos are suitable for large teams with multiple projects. The benefits aren’t necessarily obvious with a handful of small projects. Mono repos work best at a scale where there would be an observable inefficiency with a multi-repo approach.
Monorepos are not the same as monoliths. A monolith usually describes an application where the data and presentation layers are intermingled. Every time a change is made, the whole system is deployed.
Monorepos generally encapsulate multiple systems. They have multiple output artifacts such as API, website, and mobile app. Not all artifacts need to be produced for every change. Monorepos are intended to facilitate code sharing and refactoring. They are not intended to result in a closely linked system that is artificially linked together.
The pattern is not for every team. In many cases it is easier to work with multiple repositories. They often make more sense and are easier to master. You don’t have to resolve merge conflicts in different parts of the system and it’s easier to handle releases. CI pipelines will be faster because you won’t be testing every project in every pipeline.
Dedicated repositories also provide a cleaner commit history. Monorepo histories are polluted by commitments made to every project within the repo. This makes it more difficult to keep track of how individual components have evolved.
Multiple repositories are easier to integrate with version control software such as GitHub and GitLab. These tools are based on a one-to-one mapping between repositories and projects. It can be cumbersome to keep track of issues and retrieve requests in a monorepo. You need to use tags carefully to target each problem at the right project.
Finally, keep in mind that most organizations with monorepos use specialized infrastructure to support them. Git is not designed for monorepos, and it can struggle if you get enough scale. Having millions of objects in your commit history can result in delays when Git has to cycle through the graph.
The monorepo pattern simplifies code sharing and improves the visibility of your assets. This comes at the cost of a clean commit history, an increased risk of merge conflicts, and poor support for popular tools. You may also experience performance issues as the monorepo grows.
The transparency of a mono-repo is not suitable in all scenarios. If you are in a tightly regulated environment, you may need to use separate repositories so that you can enforce proper access controls. Monorepos also increase the risk of loss or theft of an employee’s device. People with physical access would be able to view all of your code rather than just the projects relevant to that person.
The decision to use a monorepo should be based on your own projects, their cross-project dependencies, and your team members. Don’t look to the big technology companies and expect to observe their successes in your own projects. There’s more to a good code culture than the type of repository you use. Mono repos make the most sense when people are already working cross-project freely of their own accord.