From efb76f222a2c8c112cf71dc6b6dc14fd3973d060 Mon Sep 17 00:00:00 2001 From: SauravDhakal Date: Mon, 28 Sep 2026 21:16:49 +0545 Subject: [PATCH] post: Added provider and dependency injection one --- content/posts/provider-and-de-in-nestjs.md | 133 +++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 content/posts/provider-and-de-in-nestjs.md diff --git a/content/posts/provider-and-de-in-nestjs.md b/content/posts/provider-and-de-in-nestjs.md new file mode 100644 index 0000000..2cf27f7 --- /dev/null +++ b/content/posts/provider-and-de-in-nestjs.md @@ -0,0 +1,133 @@ +--- +title: "Understanding Providers and Dependency Injection in NestJS" +date: 2026-09-28T18:50:00+05:45 +draft: false +tags: ["nestjs", "backend"] +description: "Concept of dependency injection in NestJS" +--- + +When I first started working with NestJS, registering providers (and controllers) inside a module felt like nothing more than a chore. + +It was one of those things I did because *“that’s just how Nest is designed.”* + +Even after I learned that modules exist to build an application graph, which it uses internally to resolve relationships and dependencies between modules and providers, the idea still felt vague and abstract. I understood **what** was happening, but not really **why** it worked the way it did. + +Recently, I decided to take a deeper dive into how providers are registered and how Nest actually injects them. It turned out to be far more interesting than I expected. + +Here’s what I learned. + +## First, let’s understand what Dependency Injection is. + +Wikipedia defines Dependency Injection(DI) as: + +> **Dependency Injection** is a programming technique in which an object or function receives other objects or functions that it requires, as opposed to creating them internally. + +Let’s look at a simple example. + +Imagine a restaurant application. When a user’s order is ready for pickup, a notification needs to be sent. + +```tsx +class OrderService { + // code operating over orders + + const notificationService = new NotificationService() + notificationService.notify(userId, message) + + // ... +} +``` + +Here, `OrderService` handles order-related logic, and `NotificationService` handles notifications. + +However, because `NotificationService` is instantiated directly inside `OrderService` using `new`, this **is not** dependency injection. + +Now compare that with this: + +```tsx +class OrderService { + constructor( + private readonly notificationService: NotificationService, + ) {} + + // code operating over orders + notificationService.notify(userId, message) + + // ... +} +``` + +This is dependency injection. + +`OrderService` no longer cares about **how** `NotificationService` is created. It simply declares that it needs one, and something else provides it. That instance can also be cached and reused across every class that needs it, if configuration is same. + +## Why Dependency Injection? + +Dependency Injection helps by: + +- Reducing coupling between classes +- Making testing easier (you can inject mock dependencies) +- Encouraging modular, maintainable code + +## How Dependency Injection Works in NestJS + +In NestJS, the basic flow looks something like this: + +1. Define a provider using `@Injectable()` +2. Register that provider with Nest +3. Ask Nest to inject it using constructor-based injection + +Registration usually happens in a module: + +```tsx +@Module({ + providers: [DemoService], + controllers: [DemoController], +}) +export class DemoModule {} +``` + +At this point, Nest becomes responsible for creating and managing instances of `DemoService`. + +## Nest’s IoC Container (The Missing Piece) + +NestJS uses an **IoC (Inversion of Control) container** to manage dependencies. + +You can think of this container as a **key-value** **registry**: + +- **Keys** are called *tokens* +- **Values** describe how to create or retrieve a dependency + +When we write: + +```tsx +providers: [DemoService] +``` + +Nest internally expands it into a standard provider definition: + +```tsx +providers: [ + { + provide: DemoService, + useClass: DemoService, + }, +] +``` + +In this case: + +- The **token** is `DemoService` (the class itself) +- `useClass` tells Nest which class to instantiate when that token is requested. + +So when Nest encounters: + +```tsx +constructor(private readonly demoService: DemoService) {} +``` + +1. Nest looks up the `DemoService` token in the IoC container +2. It finds the matching provider record +3. It resolves the provider (`useClass` in this case) +4. The instance is created (or reused, since providers are singletons by default) +5. The resolved instance is injected into the class +