Designing a Polyglot Monorepo Project
Posted on February 11, 2023 • 3 minutes • 501 words
Table of contents
What is a Monorepo
A monorepo is a fancy way of saying “I’m dumping all my code in one repository”. The alternative is having a repo per project. So for example, you frontend can live on one repository, and the backend in another. In a monorepo, it’s all in one place. Frontend, backend, tooling, that weird-but-useful utility project no one wants to talk about, it’s all there.
Disadvantages of Monorepos
An obvious disadvantage is bloat. This single repo might get annoyingly big and slow to pull and push. If you’re working in a team, this repo will get big, and you’ll have to make peace with the fact that every time you run git pull
, you’ll get a whole lot of changes in a whole bunch of folders that you know nothing about.
Advantages of Monorepos
This is where I want to spend some time. There are a few main advantages that I want to focus on.
The first advantage is code sharing. This is more than just utility functions, the code can share network interfaces. The projects do not need to be written in the same language, but there does need to be a way to translate a shared language into each language of the different projects. For example, you could have a project where the backend is written in Go, the frontend web is in TypeScript, and the mobile app is in Dart. You could then have your classes defined as a JSON schema, and a tool can take this schema and translate it to concrete classes (or structs) in the different languages. The benefit of doing this is clear when it comes to network requests. Network contracts can be generated, where all the projects have concrete classes (or structs) of what each endpoint expects as input and returns as output. This makes it possible to have compile time checks and it eliminates an annoying source of bugs that comes from a lack of alignment between projects on the network layer. Compile time checks for network contracts is really, really nice.
The second advantage is that the code shares a deployment pipeline. This makes testing and deploying all the separate pieces of a project more pleasant. Of course this needs to be done right, otherwise the deployment pipeline will be bloated as well and all the teams will step on each others’ feet. If it’s done right though, the repo can reap the benefits of a shared deployment stack, where infrastructure resources can more easily be setup and shared, and all deployments can be monitored from a single place.
See It in Action
I have a test project that puts the monorepo to the test. For the above mentioned class generation, I have a custom solution using EJS templates that translates a JSON schema to each of Go, TS, and Dart.
I go in depth and discuss how this project is setup in the README file, so go ahead and check it out!