Published in February 10, 2025
Probably a lot of time has been wasted this way.
People often praise its “structured approach to NodeJS backend development”.
Typically, they have read briefly through the documentation and decided it was a great way to “put everyone on the same page” as the framework is opinionated.
Yet if the documentation looks promising, that doesn’t mean the framework
can’t have some quirks at scale that can make you lose a lot of time.
NestJS uses classes with dependency injection. TypeScript itself can be painful with circular references when using classes.
When you add decorators and dependency injection, it can quickly become a nightmare where your last resort is to use the forwardRef
utility everywhere.
Every time one creates a service in NestJS, one has to follow the same process:
providers
field.Now, every time someone wants to use a service from another module, they need to do the following:
exports
field, add it to this field.imports
field, add it.That’s extra work that doesn’t exist in other frameworks. The more modules you create, the more time you will waste.
The documentation uses a CatsModule
example, which probably incited many companies to do one module per entity.
Therefore, they went into a hell of exports, imports, and circular dependencies.
Dependency injection has another drawback—it doesn’t play well with hot reloading.
That’s because, in most cases, it will have to reconstruct the whole dependency tree on each reload when developing.
To this, add that by default, it uses tsc
(the TypeScript compiler), so the type-checking runs on each reload, making things even slower.
This is a misfeature also because the server won’t restart if you have a TypeScript error in your code, which is annoying when developing.
tsc
cannot compile TypeScript inside dependencies, so you cannot use monorepo internal packages out-of-the-box with NestJS.
There is a monorepo mode, but that relies on Webpack, which bundles all the backend code into a single file (which we don’t need in general).
You can take a look at Fastify, which is more or less a more convenient variant of Express.
I’m not a big fan of its encapsulation system, but you’re not forced to use it.
This can just be a simple HTTP adapter layer, and your business logic can be independent of any framework.
You can also check out vite-plugin-node
for hot reloading.
As far as I know, this is the only way in NodeJS to have hot reloading without restarting the server—this is extremely fast.
Many people think that if they use a micro-framework, they will necessarily end up with spaghetti code.
In my experience, this is not true—it really depends on how you work with your colleagues.
I’ve seen some codebases using NestJS that were extremely messy, and others using micro-frameworks that were well-organized and easy to work with.
The difference was that the team producing a well-organized codebase had coding standards and a high level of expectancy on code quality,
especially during code reviews.
The team using NestJS had no standards—everyone was doing things their own way, and this quickly became a mess.
So NestJS won’t save you from a messy codebase if you don’t make the effort to define standards and work on code quality.