Incremental Builds with the Nx Cache

Speed up the build performance of your Angular application with the Nx Cloud

cover-image
portrait-image

Once your application is growing, the build times and testing times are growing as well. This affects all of the developers locally running the application on their machine but also affects the build pipeline. It is not rare to see build/test times of more than 10 minutes and even more. In order to improve the developer experience and reduce the time the build pipeline takes, you should consider going for an incremental build and remote caching. There are multiple ways of achieving this goal, but easiest solution is to use the Nx Cloud, which I will introduce in this article.


The main idea behind Incremental Builds is to slice an application into mini tiny buildable pieces and cache them. When the cache is hot, meaning it has many artifacts stored, a new build can be avoided if the desired artifactes is already existing in the cache. In that case we would just pull from the cache, which is a lot faster than executing a task that might take minutes. When using Nx, you are already making the benefit of the built-in caching which by default is done locally. Obviously, it might be a great idea to share a remote cache within a team to always have a very hot cache.

comparison
https://nx.dev/more-concepts/incremental-builds

Requirements

In order to get the benefit out of incremental builds, there are two main requirements that must be fulfilled, because otherwise the remote caching would not be effective. First, you have to have a very fine-grained library slicing, ideally, that a library does not contain more than 7 items. Additionally, the dependency flow of these fine-grained libraries make a huge impact because if there are no good boundaries, a rebuild of one library will likely cause most other libraries to be rebuilt as well. In order to avoid that, you should follow the Enterprise Monorepo Angular Patterns . Another important requirement, is to have buildable libraries. By default, libraries in an Nx monorepo are not buildable, because Nx can do some optimizations that way. But in the case of incremental builds, we have to specifically create buildable libraries with the --buildable flag.

npx nx generate lib someLib --buildable

Nx Caching

Caching
Caching

Nx, by default, is already caching locally into a .cache folder in the node_modules . For the caching it is using a hashing algorithm that takes the node version, projects, task, global configurations into consideration to generate a unique hash value. That means that if you were to add only a single space to a file, the calculated hash value would look entirely different, causing a new build. Hence, it is of big importance to always use a pre-commit hook for prettifying the code using something like husky. This is cache is stored in the node_modules and therefore owned by the local developer and is cleared whenever the node_modules are removed.
Anyways, this already works locally, eventhough not very effectively. Now, in the case of having many buildable libraries, some of them almost always can be retrieved from the cache when they did not change.

Nx Task Graph

Since the release of Nx 15.3, we now have the possibility to not only interactively inspect the project graph, but now also the task graph. That way, we can see which library builds are dependent on each other, hence indicating which libraries might trigger a rebuild of other libraries. All you have to do to see this graph, is to run the following command and select the Task option on the top left in the menu.

npx nx graph

Nx Task Graph
Nx Task Graph

Nx Cloud

The Nx Cloud offers Distributed Task Execution and Remote Caching basically out of the box without much setup required. So, if you followed the Enterprise Monorepo Angular Patterns carefully, this step is the easiest, because it only consists of one command.

npx nx connect-to-nx-cloud

Simple as that! Nothing else needed and you are good to go!

Now all of your developers can connect to the remote cache and benefit from the shared caching and reduce build times drastically.

Conclusion

Incremental Builds can be achieved by using a remote cache, which a team of developers shares. It is necessary to have fine-grained buildable libraries that are as independent of each other as possible, such that a lot can be drawn from the cache. In order to use a remote cache, you can either use the Nx Cloud and have everything work out of the box, or you could go ahead and implement a custom remote cache within a custom task runner.

GitHub Repository

Comments