跪拜 Guibai
← All articles
Backend

NestJS Isn't Just Express with Decorators — It's a Factory That Assembles Your Backend

By 东风破_ ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

NestJS imposes a module-controller-service convention and an IoC container on Node.js backends, which means teams inherit a uniform project skeleton instead of negotiating structure per codebase. For developers coming from Spring or Angular, the decorator-driven DI and modularity feel familiar; for those used to raw Express, the tradeoff is more files upfront in exchange for testable, decoupled services at scale.

Summary

NestJS layers a strict architectural contract on top of Express or Fastify, built on the factory pattern, decorators, and dependency injection. `NestFactory.create(AppModule)` acts as a single production entry point that hides the internal assembly of HTTP, WebSocket, and microservice transports. Decorators like `@Controller`, `@Get`, and `@Injectable` attach routing and metadata to classes without touching the original code, keeping route declarations separate from business logic. The IoC container then auto-instantiates services and injects them into controllers, so a constructor parameter typed with a service class just works — no `new` required. The project enforces a three-file convention per business module: `module.ts` declares dependencies, `controller.ts` handles requests, and `service.ts` holds the logic. A standard scaffold gives you `main.ts` as the bootstrap entry, a root `AppModule` that imports sub-modules, and a `tsconfig.json` pre-configured to enable experimental decorators. The result is a codebase where every NestJS project follows the same pattern: factory boot, module tree, controller routing, service logic.

Takeaways
`NestFactory.create(AppModule)` is a factory method that hides the assembly of HTTP, microservice, or WebSocket transports behind a single call.
Decorators like `@Controller('todos')` and `@Get()` separate route declarations from handler logic, replacing manual `app.get()` wiring.
Every business feature gets its own directory with `module.ts`, `controller.ts`, and `service.ts` — a three-file convention enforced by the framework's design.
Services marked with `@Injectable()` and registered in a module's `providers` array are automatically instantiated and injected into controllers by the IoC container.
TypeScript decorator support requires `experimentalDecorators` and `emitDecoratorMetadata` set to `true` in `tsconfig.json`, which the `nest new` scaffold handles automatically.
The root `AppModule` assembles the application by importing sub-modules, registering controllers, and listing providers, forming a dependency tree that mirrors the project's directory structure.
Conclusions

Framing NestJS as three design patterns — factory, decorator, and dependency injection — makes its architecture legible to developers who might otherwise bounce off the heavy use of `@` syntax and module boilerplate.

The Mixue ice-cream factory analogy is unusually effective: it maps `NestFactory.create()` to a real-world order-dispatch pattern without oversimplifying the IoC container's role.

NestJS's convention of one directory per business module with a fixed three-file structure is less about the framework's runtime needs and more about eliminating the decision cost of organizing code across teams.

Concepts & terms
Factory Pattern
A creational design pattern where a factory method or class hides the instantiation logic of different product classes behind a single interface. In NestJS, `NestFactory.create(AppModule)` acts as the factory that assembles and returns a fully configured application instance.
Decorator Pattern
A structural pattern that dynamically attaches additional responsibilities to an object. In NestJS, TypeScript decorators like `@Controller()` and `@Injectable()` add routing, metadata, and injection markers to classes without modifying their source code.
IoC Container / Dependency Injection
Inversion of Control container that manages object creation and wiring. NestJS's container reads `@Injectable()` markers and module `providers` arrays, then automatically instantiates services and injects them into controller constructors, eliminating manual `new` calls.
NestFactory
The static factory class in NestJS used to bootstrap an application. `NestFactory.create(AppModule)` initializes the IoC container, resolves the module dependency tree, and returns an application instance that can listen for HTTP, WebSocket, or microservice connections.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗