Skip to main content

Command Palette

Search for a command to run...

Why I use NestJs for past 5 years

Updated
9 min read
Why I use NestJs for past 5 years
I

Graduated from Telkom University with a degree in Computer Science, specializing in software development and systems design. Recently contributed to Supernova Palapa Nusantara as a Software Engineer, where efforts focused on developing and implementing software solutions, improving project reliability, and collaborating with multidisciplinary teams. Key competencies include software architecture, quality assurance, and backend programming.

At Supernova Palapa Nusantara, contributed to software architecture enhancements with a focus on system reliability and project goals. Previous roles involved optimizing and developing web platforms, such as university systems, in collaboration with cross-functional teams. Brings a collaborative approach and a commitment to delivering impactful digital solutions that align with organizational objectives.

Introduction

It’s hard to believe, but I’ve been using NestJS for almost five years now. My journey started back in college when I was offered a project to build a backend system for a vessel tracking website based on MarineTraffic. At that time, I had just begun learning Node.js and this was my very first real-world project using it.

When facing a real project, the first questions that came to mind were: What are the requirements? What kind of backend architecture would be suitable? And most importantly, which framework could support those needs? My search for the right framework naturally began with the most popular option at the time, one and only Express.js.

Express, with its tagline “Fast, unopinionated, minimalist web framework for Node.js,” seemed appealing at first. The flexibility was impressive, almost too impressive. While exploring, I quickly found myself falling into a rabbit hole: Which companion packages should I use? How should the folder structure look? Should I follow MVC? Should I write in JavaScript or switch to TypeScript? And the list of questions kept growing.

That’s when I realized I might need to refine my search. Instead of looking for a minimal framework, I needed something more structured, an opinionated Node.js framework. And that’s when I discovered NestJS.

Key Reasons I’ve Stuck with NestJS for 5 Years

  1. TypeScript as a First-Class Citizen

    TypeScript by default? Yes, please! Many developers argue that strongly typed languages make things unnecessarily complicated. That might be true for small projects, but when you’re building something more solid, TypeScript acts like a safety net for JavaScript. It saves you from those dreaded runtime type errors that can appear out of nowhere.

    With TypeScript, functions, objects, and even complex structures come with helpful snippets and autocomplete support. This speeds up development and reduces guesswork. NestJS embraces TypeScript from the ground up. When creating a new NestJS project, TypeScript is the default choice, though you can still opt for JavaScript if you want.

    But honestly, once you’ve enjoyed the safety, clarity, and productivity boost of TypeScript, who would want to go back to plain JavaScript?

  2. Clean Architecture

    NestJS introduces a modular folder structure that feels both organized and intuitive. This is quite different from the traditional MVC approach, where you typically separate files by their function, controllers go into a controller folder, models into a model folder, and so on.

    With NestJS, the modular concept groups everything based on the domain of your application. For example, the UserModule contains the controller, service, entity, and repository related to users. If there’s an error in login, you know exactly where to look, the AuthModule. Everything related to authentication stays inside that module and nowhere else.

    This modular design makes projects much easier to navigate and maintain, especially as they grow larger. Instead of hunting across multiple folders, you can focus on a single module that fully encapsulates a feature or domain.

  3. Dependency Injection

    Impressed with NestJS’s modular architecture? Hold on… it gets even better once you meet its powerful dependency injection (DI) system. Since NestJS takes inspiration from Angular, it also adopts Angular’s DI pattern.

    Modules in NestJS become even more powerful thanks to DI. For example, if Module A needs to use a service from Module B, you simply export the service in Module B and import that module into Module A. The DI container will take care of providing the instance wherever it’s needed.

    Another benefit of DI is performance optimization. By default, NestJS services are singletons, meaning only one instance is created and shared across the application. This saves memory and ensures consistent state management. Of course, if your use case requires it, you can also configure services to be request-scoped or transient.

    In short, DI in NestJS isn’t just a convenience, it’s a cornerstone that keeps your application clean, modular, and efficient.

  4. Recommended Packages

    Remember the headache of choosing companion packages in Express? With NestJS, that problem is greatly simplified. The framework not only recommends optimal packages but also provides official wrapper modules for seamless integration.

    Take Mongoose, for example. Instead of wiring it up manually, NestJS offers @nestjs/mongoose, a dedicated module that integrates perfectly with the framework’s architecture. Need validation? NestJS supports class-validator and class-transformer out of the box. Need security? There’s built-in support for tools like helmet. Want API documentation? The @nestjs/swagger module automatically generates a complete OpenAPI specification from your controllers and DTOs, no need to handwrite specs.

    By curating and wrapping popular libraries, NestJS saves developers from decision fatigue and ensures best practices are followed by default.

  5. Community & Documentation

    Back in 2020, there was no ChatGPT to turn to when you got stuck. The first lifeline was always documentation. Thankfully, NestJS provides one of the most beginner-friendly documentations out there. It’s structured almost like a step-by-step guide, yet it doesn’t shy away from diving deep into technical details when needed.

    The second lifeline was, of course, the community. The NestJS Discord server has been active for years, and asking questions there often brings direct answers from experienced developers, including some of the core contributors themselves. The combination of high-quality documentation and a responsive community makes NestJS approachable for beginners while still powerful for advanced users.

Comparison with Other Frameworks

  • Express: great for getting started quickly, but less structured as your application grows

    Express offers a high level of flexibility. For developers who already have strong patterns and architectural practices in place, Express can feel like the perfect choice. It’s lightweight and works especially well for small services or microservices that handle a single responsibility, such as authentication or login endpoints. However, without clear conventions, large-scale projects in Express can become difficult to maintain, especially for teams with varying levels of experience.

  • Koa / Hapi / Fastify: flexible but less opinionated

    Similar to Express, frameworks like Koa, Hapi, and Fastify focus on flexibility and performance. They give developers freedom to choose how to structure their applications. While this can be powerful, it didn’t match what I needed at the time.

    An opinionated framework like NestJS provides more than just convenience, it creates consistency. For a new team member, onboarding becomes easier: just follow the documentation and established patterns. For experienced developers, the workflow remains consistent because everyone is aligned by the same architectural design. This shared structure reduces confusion, accelerates collaboration, and keeps projects maintainable as they scale.

Real-World Use Cases

Over the years, I’ve implemented NestJS in a wide range of backend systems: asset management, ticketing systems, auction platforms, e-commerce applications, university education systems, and more. Even projects requiring real-time capabilities, like the vessel tracker I worked on, were achievable thanks to WebSocket and Socket.IO support.

Scaling with NestJS is straightforward thanks to its modular architecture. In one project, the authentication feature became the most frequently accessed part of the system, since every login and token validation request passed through it.

Scaling up the entire application just to handle this load would have been wasteful. Instead, we were able to extract the AuthModule and run it as a separate service within the same NestJS ecosystem. That way, only the authentication workload was scaled independently, without touching the rest of the application.

This modular design makes NestJS highly adaptable, whether you’re building monoliths, microservices, or a hybrid architecture.

Lessons Learned Over the Years

  • Consistent Code Conventions

    NestJS’s opinionated design enforces best practices by default. This means every project follows a familiar structure, regardless of when it was created or who worked on it. Switching between projects or even revisiting an old one, feels seamless because the folder organization and code patterns remain consistent. This consistency reduces cognitive load, speeds up onboarding, and helps teams maintain codebases more effectively over time.

  • Easier Testing with Dependency Injection

    One of the most frustrating parts of writing tests is setting up all the services and dependencies you need. Thanks to NestJS’s built-in dependency injection system, this process becomes much simpler.

    With the @nestjs/testing package, you can create a TestingModule that automatically provides the required services and their dependencies. This makes it easy to instantiate only what you need for the test, without manually wiring everything together.

    Dependency Injection not only simplifies test setup but also encourages cleaner, more maintainable unit tests across your application.

  • Faster Onboarding for New Developers

    When junior developers ask me which Node.js framework they should learn first, my answer is always NestJS. Several juniors I’ve mentored started with it, and they adapted quickly. The opinionated structure and clear documentation allowed them to focus less on setup and more on delivering features. In no time, they were completing the tasks I assigned with confidence.

Drawbacks of NestJS

  • Steep Learning Curve at First

    It’s true! The first time you try NestJS, the learning curve can feel steep. Concepts like decorators, dependency injection, and other unfamiliar terms may seem overwhelming at the beginning.

    But don’t worry. NestJS is often described as “easy to learn, hard to master.” You can start building applications quickly without needing to fully understand every concept under the hood. For example, it’s enough to know what a decorator does without diving into its internals.

    As you grow more comfortable, NestJS reveals its depth. Exploring advanced concepts allows you to fine-tune performance, optimize architecture, and unlock the full potential of the framework.

  • Quite a Bit of Boilerplate

    Unlike Express, where you can get a basic API running in just a few lines, NestJS requires more code upfront when starting a project. At first, this can feel like a lot of boilerplate.

    The good news is that NestJS provides a powerful CLI to help. Need to create a module? Just run nest g module <module-name>. Want a complete resource with controller and service? The CLI can generate that too.

    These tools make it easy to manage the initial code overhead, and the comprehensive CLI effectively offsets the boilerplate, allowing you to focus on building features rather than wiring up structure.

  • Sometimes Feels Too “Opinionated”

    This really comes down to personal preference. Some developers see it as a drawback, while others see it as a strength. It’s a double-edged sword. There are moments when creating even a single module feels like a lot of coding, even with the CLI helping out. But once it’s set up, the structure is solid, maintainable, and consistent. That initial extra effort pays off in the long run, especially as projects grow larger or when new team members join.

Conclusion

If you ask me which Node.js backend framework I recommend, my answer is always NestJS. Even today, I continue to use it whenever the project ecosystem is Node.js.

If you face the same challenges I encountered back in 2020, chances are you’ll end up discovering NestJS at the end of your search. It’s ideal for building solid backends, quickly delivering MVPs, and scaling both vertically and horizontally.

After five years of experience with NestJS, I’m now preparing a starter template that makes it even easier to get a backend up and running for MVP projects. I’ll share the GitHub repository soon, so stay tuned.