Why you shouldn’t use NestJS

Blog Image

Naym Hossen

Published in February 10, 2025

Being in the NodeJS ecosystem for a few years, I’m surprised by how many startups use NestJS and still face the same issues.

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

Why you shouldn’t use NestJS

can’t have some quirks at scale that can make you lose a lot of time.


The problems

Circular references

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.

Nest modules are a waste of time

Every time one creates a service in NestJS, one has to follow the same process:

  1. Find which module this service belongs to.
  2. Add the service to the module’s providers field.

Now, every time someone wants to use a service from another module, they need to do the following:

  1. Find out in which module the service to use belongs to.
  2. If it’s not in the module’s exports field, add it to this field.
  3. Find out in which module we want to use the service.
  4. If the source module is not in the module’s 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.

Slow hot reload

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.

Poor support for monorepos

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).


What to use instead?

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.


But how to avoid spaghetti code?

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.