Why Use Nx for Monorepos
Written by Preston Lamb
Posted on Sep 20, 2019
Recently, we started a new project at work. Actually two projects. We needed an application where people could sign in and see information about their account, and another one where they could search for a doctor or facility where they could receive care. The wrinkle is that the search functionality needed to be available inside the member portal application, and be available as a stand-alone application. Because of that, we decided to build the two applications inside a monorepo, where they could share all the code they needed. It allowed us to write the code one time, and use it in multiple places. There's more than one way to do this, including packaging up the code and pushing it to NPM or a private registry, but in my opinion the monorepo is the simplest way to share the code. To learn more about Nx, check out their site, nx.dev.
So, what is a monorepo? And why should you use one? Do you need to use one? Is it just a fad?
These were all questions I asked as I was looking into the options we had when we were starting our new project. First, a monorepo is a source control repository that contains code for multiple projects. Over the last few years, I've seen our company go from a monorepo to having each project be in its own repo, and now going back (selectively) to monorepos. I think that as far as should you use one, that completely depends on your preference. I don't think there's a one-size-fits-all answer. Each project and each company is different. They have different constraints, and different preferences. Think about these before you make the choice to go with a monorepo. And as for it being a fad, that part may be somewhat true, that it's becoming more popular to put your code in a monorepo again, but there are a lot of big companies (like Google) who have all or most of their codebase in a monorepo. If it works for them, I think that most companies can make it work, if they want to, for them as well.
In our situation, a monorepo made sense and so we decided to go with it. If you do decide to go with the monorepo, I highly recommend using Nx by Nrwl. Their suite of tools has been extremely helpful during the development process. Let's talk about some of why I've enjoyed Nx so much.
Nx is a suite of tools provided by Nrwl to help in creating applications, especially monorepos. Their tools allow you to use only Angular, only React, React and Angular, and on top of that you can throw in Nest.js for an API project as well. They set up the build pipeline, and also provide other tools for the development process. They also provide an opinionated way of organizing your code so that you can easily share as much as possible between your apps.
One of the things they offer is an
affected command that will analyze the repo and do certain actions (build, test, etc) for only the applications that are affected by a change. So, let's say you have two apps,
App2, and they each have their own specific libraries that accomplish things inside that app and inside that app alone, and then you have a set of shared libraries that do things for both
App2. If you make a change to the libraries specific to
App1 only, and then run the
affected:test command, for example, only
App1 tests will run. If you made a change to the shared libraries, though, then both
App2 would have their tests run.
The ability to run tests or builds on affected apps becomes more and more important the more libraries and apps your monorepo has. If your repo had 10 apps, and you made a change to a single page in one app that didn't affect the other 9 apps but still triggered a build on all 9, each build and deploy would naturally take much longer than needed. Not to mention tests, as well! Those become more intrusive as the size of your monorepo grows.
The opinionated structure is another thing that I like. I like that I can build the apps and libraries according to some standard and have developers come in to work with me and know exactly what is going on and how to be effective. I know some people don't like that and they like to make decisions like this on their own, but I don't think it's the most effective way for teams to work. It also assists in trying to find some component or service that I need. If I know it's a UI component like a card component that's used throughout the app, I know the best first place to look is the
SharedComponentsModule. If it's a service to get information about a user, I can go to the
UserDataAccessService, for example. That code organization makes it possible for new developers to be effective as quickly as possible when joining the project.
(Don't mind the names I used there, it's just an example.)
What's missing from the developer experience, so far? In my opinion, the only thing that's missing so far is a clear example of how to deploy apps from a monorepo to different environments. On our team, we already had a deployment process in place for Docker Swarm and Kubernetes. But on those applications, we only had one Angular application in the repository. All we needed to do was build a Docker image and deploy it. The monorepo is slightly different, where we don't want to build every application on every commit to the master branch. Having a couple examples of best practices for deploying to Google Cloud or AWS for example, would be great. I realize that it may be overkill for them to provide that as well, but there are a lot of tips and tricks that Nrwl provides at connect.nrwl.io. I just wish there was one for deploying apps.
Overall, I've been really happy working in our monorepo. Ours only has two Angular apps in it for now, but it may continue to grow. I also just started a full stack workspace for a personal project to try it out, and I'm excited to 1) learn how to use Nest.js and 2) to use it right alongside the Angular application. If a monorepo is an option for you and you think it'll benefit your project, I highly recommend it and definitely recommend using Nx to help!