Scaling our Largest Angular Platform with Nx

The story of how we scaled our Angular platform from 10 developers to 40 developers using a monorepo.

Tytus Planck
84.51°

--

By Tytus Planck, 84.51° Senior Software Engineer

Photo by 84.51° and Nrwl.

In the age of ever-expanding engineering organizations, building large platforms that require the sharing of assets across teams is paramount. Our engineering organization has rapidly expanded over the course of a few years and this has put us in the position to find tools that improve the developer experience at 84.51°. One of the most powerful tools we’ve used in our Angular development has been Nrwl’s Nx.

Our journey started with a single developer team of about 10 engineers working on a brand new Angular UI for our advertising business called 84.51° Prism. The repository and app were built using the basic Angular CLI and created a project structure most Angular developers would recognize (a single app). This worked great as the small team of developers built out an initial MVP (minimum viable product). As the aspirations for 84.51° Prism grew, so did the team of engineers working on the product. We needed an effective way to spin up new UI teams that were seamlessly integrated to the platform yet independent enough to manage releases separately. Our solution? A monorepo backed by Nx.

Nx is a tool built by Nrwl meant to simplify the organizational challenge of maintaining and sharing code between multiple front-end applications. In short, we chose Nx to allow our developers to easily share code while also retaining the ability to independently deploy their team’s individual application.

Transitioning to Nx

We knew our platform had big aspirations to grow so we wanted to start leveraging Nx as quickly as we could. Using Nx required us to move almost every file, so we took a phased approach to limit the number of changes.

As a first step, we created a new repo with an Nx workspace then temporarily placed our only Angular app into the app directory. This gave us an Nx workspace without a big impact to work already in process. There were some challenges converting our code over but Nrwl has a great guide and tools to handle the migration.

Next, we broke out a small portion of our original app, our “release notes” page, to another app. It was an easy slice of our code that could be moved with relatively low risk to our current work. This transition gave us the ability to independently deploy our release notes app from the rest of our app, providing a large convenience to our developers.

After the transition of our release notes app, we had the knowledge to create a documented process for us to add new apps and libs to our monorepo. We continued the process of splitting out code into apps and libs little-by-little to better leverage what Nx can offer. Since then, we’ve separated our 1 large app into 9 apps, 21 shared libs, and 42 domain specific libs, fully taking advantage of Nx.

Do I really need to complicate my project?

So why should you commit time to moving to a monorepo? Why is Nx the right tool? Will it really save you time and developer efficiency? To be honest, it depends on multiple factors. Every project, team, organization is different and monorepos fix a small set of problems. Let’s do a deep dive into the pros and cons of using Nx and why it might be the right tool for you and your team!

Benefits of using Nx

  1. Easily allows developers to share code.
  2. Creates contracts between teams that can be handled at the time of code review (pull request).
  3. Enables teams to spin up new UIs faster with the jump-start of shared code and patterns.
  4. Provides independent deployability while also allowing teams to easily integrate with one another.
  5. Freedom to use different Javascript frameworks in the same repo.

With Nx, the main driver is consistency and the sharing of code. It’s really difficult to drive and share best practices across an organization. We’ve found that Nx has allowed us to not only speed up development time by sharing code, but it’s also made it much easier for teams to learn from one another. Every time a team decides to use a new pattern or attempt a unique approach in a shared library, every other team is exposed to it. Not only does this lead to the spread of ideas, but when a PR needs reviews from a wide-range of people it properly vets the code. You are no longer silo-ed to a team full of developers that slowly start to think the same over time.

Using a monorepo has allowed us to easily share talent around our organization. As our teams agree on best practices and ways of writing code it becomes much easier to float between them. This enables further cross-pollination in our organization. I hope to address and share how we’ve been able to effectively define and manage our best practices across all our UI teams in the monorepo in a future article.

Drawbacks of using Nx

  1. Management of CI/CD pipelines are significantly more complex.
  2. External teams are now required to review PRs that touch shared code.
  3. Cross-team collaboration on agreed-upon patterns can be difficult.

Our main issue with using a monorepo is how you handle build and deploying your app. If your organization doesn’t have the right resources this can easily become burdensome. We’ve gone through multiple iterations on our CI/CD pipeline in order to make it more and more efficient. Luckily Nx offers great tools to enable this via their affected commands. However, there is a learning curve compared to standing up a simple pipeline for one Angular app. We have also struggled when shared code is touched, which ends up requiring all of our team’s approvals. This can be massively frustrating for teams who are both waiting on review and being asked to review code. We’ve done our best to utilize GitHub’s code ownership features to minimize the impact.

“A Challenger Appears!”

There are pretty clear patterns on the web for sharing code — mainly the use of a package management system like NPM. One major benefit of those tools is the ability to easily manage package versions as code changes. For example, if I’m on Team A and I make a commit to shared code that includes a breaking change, Team B doesn’t necessarily have to take that change immediately. The issue with this approach is when you have so many shared libs/packages (we have 21 globally shared libs in our monorepo) between teams that managing those separate repos becomes extremely difficult.

With an Nx monorepo in this scenario, you would have to immediately address the breaking change by either fixing it for that other team or by branching the code. On one hand a small change may mean “extra work” because you’re now running tests for another app, but, on the other hand, the codebases are forced to stay in sync, further promoting code consistency.

Nx does offer organizations more flexibility though and breaks down inter-team dependencies. If the amount of sharable code is small or is universal to all teams, it might make sense to go with this approach.

Conclusion

Over the course of a few short years our platform has grown from one Angular app to nine independently deployable apps. Nx has been an easy to use tool that enabled our organization to grow rapidly. We’ve been able to drive consistency in our user experience through the sharing of components and code. Our monorepo has made our app creation and team on-boarding significantly more efficient. Our shared code drives our teams to work more closely together and promotes the use of similar patterns. We’ve been able to accelerate the growth of our engineering team as well as our platform through the use of a monorepo architecture powered by Nrwl’s Nx.

--

--