Why NestJS?

Why NestJS?

Teamz Lab

> TL;DR: NestJS is a progressive Node.js framework for building server-side applications. Built on top of Express (or Fastify), it provides an opinionated structure…

The analogy

Express is like a studio apartment — everything in one room, you decide where stuff goes. NestJS is like a well-designed house with labeled rooms: kitchen (services), front door (controllers), hallways (modules). Both work, but the house is WAY easier to manage when you have 50 rooms!

What is it, really?

NestJS is a progressive Node.js framework for building server-side applications. Built on top of Express (or Fastify), it provides an opinionated structure inspired by Angular, using modules, controllers, and services. It includes powerful features like Pipes, Interceptors, Filters, Middleware, and custom Decorators.

Why it matters in the real world

NestJS is used by Adidas, Roche, Autodesk, and many startups. It's the most popular structured Node.js framework, with over 70K GitHub stars.

The 11 things you actually need to know

Built-in Structure — Module → Controller → Service pattern. Everyone organizes code the same way — no more 'where did John put that file?'

Dependency Injection — Instead of manually creating instances, you just declare what you need and NestJS delivers it. Like room service!

TypeScript First — NestJS is built FOR TypeScript. Decorators (@Get, @Post, @Injectable) make code readable and self-documenting.

Batteries Included — Validation, auth guards, Swagger docs, WebSockets, microservices — all built-in or plug-and-play.

Scalable from Day 1 — Start small with one controller. Grow to 100 modules without refactoring. NestJS scales with your team!

Rich Ecosystem — @nestjs/jwt, @nestjs/passport, @nestjs/websockets, @nestjs/graphql. Add what you need, nothing more.

Pipes — Data Transformation & Validation — Pipes transform or validate incoming data before it reaches your controller. ValidationPipe automatically checks DTOs, ParseIntPipe converts strings to numbers. Think of pipes as airport security — they inspect your luggage (data) before you board the plane (controller).

Interceptors — Before & After Logic — Interceptors wrap around your route handler. They can transform the response, add logging, cache results, or measure execution time. Like a sandwich — interceptor code runs before AND after your handler. Example: automatically wrapping all responses in {success: true, data: ...} format.

Exception Filters — Centralized Error Handling — Instead of try/catch everywhere, exception filters catch errors globally and return consistent error responses. Create a custom filter to log errors, send alerts, and return user-friendly messages. One place to handle ALL errors.

Middleware — Request Pipeline — Middleware runs BEFORE the route handler on every request. Use it for logging, CORS, rate limiting, or authentication checks. It's the bouncer at the door — checking everyone before they enter the club (your controller).

Custom Decorators — Create your own decorators like @CurrentUser() to extract the logged-in user from the request, or @Roles('admin') to mark routes. Custom decorators make your code cleaner and more readable — hiding complexity behind a simple @ symbol.

Working code example

```typescript
// The NestJS Holy Trinity 🔺
// 1. MODULE — wires everything together
@Module({
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}

// 2. CONTROLLER — handles HTTP requests (the front door 🚪)
@Controller('users')
export class UserController {
constructor(private userService: UserService) {}
// ↑ NestJS auto-injects this! Magic! ✨

@Get() // GET /users
findAll() {
return this.userService.findAll();
}

@Get(':id') // GET /users/123
findOne(@Param('id') id: string) {
return this.userService.findOne(id);
}

@Post() // POST /users
create(@Body() data: CreateUserDto) {
return this.userService.create(data);
}
}

// 3. SERVICE — business logic (the brain 🧠)
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}

findAll() {
return this.prisma.user.findMany();
}

findOne(id: string) {
return this.prisma.user.findUnique({ where: { id } });
}

create(data: CreateUserDto) {
return this.prisma.user.create({ data });
}
}

// DTO — validate input 📋
import { IsString, IsEmail, MinLength } from 'class-validator';

export class CreateUserDto {
@IsString()
@MinLength(2)
name: string;

@IsEmail()
email: string;
}
```

Line-by-line breakdown:

1. The NestJS Holy Trinity 🔺
2. 1. MODULE — wires everything together
3. Decorator that adds metadata or behavior
4.
5.
6.
7. Exporting for use in other files
8.
9. 2. CONTROLLER — handles HTTP requests (the front door 🚪)
10. Decorator that adds metadata or behavior
11. Exporting for use in other files
12.
13. ↑ NestJS auto-injects this! Magic! ✨
14.
15. Decorator that adds metadata or behavior
16.
17. Returning a value
18. Closing block
19.
20. Decorator that adds metadata or behavior
21.
22. Returning a value
23. Closing block
24.
25. Decorator that adds metadata or behavior
26.
27. Returning a value
28. Closing block
29. Closing block
30.
31. 3. SERVICE — business logic (the brain 🧠)
32. Decorator that adds metadata or behavior
33. Exporting for use in other files
34.
35.
36.
37. Returning a value
38. Closing block
39.
40.
41. Returning a value
42. Closing block
43.
44.
45. Returning a value
46. Closing block
47. Closing block
48.
49. DTO — validate input 📋
50. Importing required dependencies
51.
52. Exporting for use in other files
53. Decorator that adds metadata or behavior
54. Decorator that adds metadata or behavior
55.
56.
57. Decorator that adds metadata or behavior
58.
59. Closing block

Spot the bug

```
@Controller('users')
export class UserController {
constructor(private userService: UserService) {}

@Get()
findAll() {
return this.userService.findAll();
}
}

export class UserService {
findAll() { return []; }
}
```

<details><summary>Hint</summary>

What decorator is missing from the service class?

</details>

<details><summary>Answer</summary>

UserService is missing the @Injectable() decorator. Without it, NestJS can't inject it via dependency injection. Fix: add @Injectable() above 'export class UserService'.

</details>

Explain it like I'm five

Express is like a messy room where you put stuff wherever. NestJS is like a room with labeled shelves - toys here, books there, clothes in the closet. Both rooms work, but the organized one is way easier when you have LOTS of stuff!

Fun fact

NestJS was created by Kamil Myśliwiec in 2017 because he was frustrated that Node.js had no structure like Angular did for frontend. He basically thought 'why can't backend be organized too?' and just... built it. 😤🛠️

Try it yourself

Create a NestJS project with `nest new my-app`, then generate a module with `nest g resource cats`. Look at the files it creates — controller, service, module, DTO. Notice how they connect!


Want the interactive version?

This article is lesson 15 of **Free Full-Stack Playbook** — a free, interactive course with quizzes, a code playground, spaced-repetition flashcards, and 48 more lessons. No signup required.

- 📖 Open this lesson with quizzes + code playground
- 🎓 See the full 49-lesson curriculum
- 🏠 All 16 free courses on Teamz Lab Learning

- JavaScript vs TypeScript — Adding Superpowers to JS
- Developer Tooling — Work Smarter, Not Harder
- Variables, Types & Arrays — The Building Blocks of Data


Built by [Teamz Lab](https://teamzlab.com) — we build production mobile and web apps for clients worldwide. This free course is how we give back. Free Full-Stack Playbook's [interactive version is here](https://learn.teamzlab.com/c/js-ts-fun-book.html).


Originally published at tool.teamzlab.com

Report Page