NestJS: The Good, The Bad, and The Ugly

Would you choose NestJS for the next project?

Robert-Jan Kuyper
Better Programming

--

In the past years, I have developed numerous applications using NestJS, which have been utilized by hundreds, thousands, and even millions of customers throughout Europe. These applications were built in teams of different sizes, including start-ups, scale-ups, and corporate organizations. From modular monoliths to event-driven microservices, GraphQL and REST were all used and developed using NestJS. But with every good aspect, there is also a bad and even an ugly part.

In this article, I will share my thoughts after working on NestJS during this period. My goal is to provide developers, technical leads, and team leads with the tools they need to anticipate and address any potential issues that may arise while using NestJS.

The Good

I’ve worked in teams of different sizes, with different opinions about clean code and definitions of when an application is done. It varies from company to company, from team to team, and even from person to person. Opinions of individuals in teams are often subjective, and that can make it hard to form development guidelines and coding styles. As a matter of fact, all teams sooner or later follow the same learning curve phases, as the diagram points out.

The learning curve, all development teams go through

Here is where Nest actually proves it value by guiding teams in certain directions and offers a design pattern that already does the heavy lifting for you. Nest is highly opinionated, and that is a good thing.

The value of Nest for teams really proves itself when it comes to consistency in and over teams and consistency in their codebases. When one uses the framework, they can for example actually hop on a GraphQL application, without the need to gain deep knowledge about the ins and outs. Nest makes this possible by offering really well-documented code examples.

As businesses are moving fast, it is a great plus to use a development framework that is flexible and can actually move with the direction of the business. By using Nest your team can focus on delivery, instead of onboarding processes. New developers can easily be onboarded, and even junior developers can start contributing from the moment go, thanks to the great documentation and thriving community behind the framework.

The Bad

As with every good, there is also a bad. And to be honest, it is not always the framework that is directly responsible for it, but really often it is teams or individuals that misuse or misunderstand concepts within a framework. Though I would like to point out some areas of Nest where teams I worked with struggled on over and over again.

The circular dependency issue

Sooner or later each NestJS project will face the moment that circular dependencies are introduced. Not only can I relate from experience, but also Nest elaborates on this common issue and the community-built package nestjs-spelunker identifies similar problems as well (even though it’s focused a bit more on the dependency injection tree in general).

The circular dependency issue is quite a nasty one, that could potentially slow down the entire development team in the long run — if not solved properly. Fortunately, quite recently an article about circular dependencies was published by Trilon, where a core contributor of Nest points out a tool, called Madge, to identify circular dependencies early.

Swallowed logs on application startup

Another issue that quite often occurs alongside circular dependencies is that logs are being swallowed while an error occurred on startup. This makes it quite hard for developers to understand what actually happened.

A common approach to identify the error that was thrown is to disable aborts on an error and re-throw the error message.

This will now log the actual error in the console.

The Ugly

As with every good and bad, there is also an ugly part. And to be honest, it is not always the framework that is directly responsible for it, but really often it is teams or individuals that misuse or misunderstand concepts within a framework. Though I would like to point out some areas of Nest where teams I worked with, struggled over and over again.

Unit testing

In Nest unit testing really integrates with the framework itself. Declaring the difference between a unit and an integration team varies from team to team and even from person to person. Within Nest, testing the smallest unit requires quite some boilerplate code and knowledge of different techniques. Especially for new developers, writing tests can be complicated, as it requires them at least some knowledge about how Nest resolves its dependency injection tree.

To test a simple application you will really often stumble upon a test file that looks similar like:

In most real-world applications, however, there will be multiple dependencies for a single provider and that will heavily increase the complexity of a unit test. After a while, those tests can even become a bottleneck, as teams focus more and more on how to write a test and its dependency injection tree, instead of actual test the unit itself.

Could it be done differently? Sure, I’ve seen teams that tackle the complexity of tests by implementing logic in separate functions instead of implementing it in a class method. The advantage of that approach is that testing becomes a no-brainer, and new developers are more easily onboarded, as they all know JavaScript. Consider the following:

Although every good aspect has its drawbacks, implementing such an approach can address unit test complexity on one hand, but comes with its own trade-offs on the other.

The lack of Dynamic controllers

Nest comes with a powerful concept of providers. These providers can be custom and can be anything. Such providers become helpful once a project becomes more mature. Though it requires developers to gain quite some knowledge of how Nest resolves its dependency injection tree.

Anyway, what is actually missing is the counterpart of such custom providers, which are custom controllers. Even though such controllers, are according to the creator of Nest completely contrary to the ideas of Nest, they are actually really helpful when a project grows. To overcome the limitations of Nest here, one could implement a factory approach as described in this GitHub thread:

One can consume the factory through (but not only) Dynamic Modules:

Though with every good there is a bad, and implementing such an approach tackles the dynamic controllers on one hand, you’ll leave the Nest opinionated patterns for controllers on the other.

Conclusion

Nest is a really mature well-documented go-to framework within the Node landscape. Though with every good, there is a bad and there can even be ugly. So when making the decision for a framework like NestJS, make sure you identified potential issues your team will face.

The final question that arises — would I choose NestJS for my next project. Well, like always, it depends ;)!

--

--