Support Online
Skip to main content

NestJS Dependency Injection Guide

What will you learn in this guide?

In this guide, you will learn how the NestJS Dependency Injection (DI) architecture works.
You will understand the concepts of DI and IoC with simple examples and see why NestJS focuses on this structure.

🧠 Technical Summary

This guide explains how to use Dependency Injection in NestJS.
The aim is to reduce the close dependency between classes and establish a sustainable architecture.
Steps: JavaScript classes → DI need → NestJS DI system → Module, service and controller relationship.


Prerequisites

The following should be ready before continuing:

  • Node.js (v16 and above)
  • VS Code or similar editor
  • Postman or similar API testing tool
  • NestJS basic concepts (Module, Controller, Provider)

A Brief Overview of JavaScript Classes

In JavaScript, classes are templates used to create objects.

class Greeting {
sayGoodMorning() {
return "Hello, Good Morning";
}
}

const message = new Greeting().sayGoodMorning();
console.log(message);
  • This code shows how to create an object from a class.

Constructor Usage


class Greeting {
constructor(message) {
this.message = message;
}

sayGoodMorning() {
return this.message;
}
}

const greeting = new Greeting("Hello, Good Morning").sayGoodMorning();
console.log(greeting);
  • This structure allows giving data to the class from outside.

A Service Design Without DI

  • In the example below, the services are tightly connected to each other.

class DatabaseService {
createPost(post) {
return `Creating ${post.title}`;
}
}

class BlogService {
constructor() {
this.databaseService = new DatabaseService();
}

createPost(title, content) {
return this.databaseService.createPost({ title, content });
}
}
  • Problems of this approach:
  1. Services cannot be changed.

  2. Writing tests is difficult.

  3. The code is inflexible.


Dependency Injection with NestJS

  1. Classes are not created manually in NestJS.
  2. Framework generates objects for you.

import { Injectable } from '@nestjs/common';

@Injectable()
class DatabaseService {
getAllPosts() {
return [];
}
}

@Injectable()
class BlogService {
constructor(private databaseService: DatabaseService) {}

listPosts() {
return this.databaseService.getAllPosts();
}
}
  • This structure uses constructor injection.

What is Inversion of Control (IoC)?

  1. IoC is the transfer of control from the application to the framework.

  2. NestJS manages the lifecycle of objects itself.


Gains:

  1. Loosely coupled architecture

  2. Easy testability

  3. Cleaner code


Dependency Injection Flow in NestJS

  1. Provider is defined.

  2. It is added into the module.

  3. It is injected into the controller or service.

  4. NestJS IoC container manages the object.


Creating a NestJS Project


npm i -g @nestjs/cli
nest new nest-di
cd nest-di
  • These commands create a new NestJS project.

Creating Resources


nest g resource players

This command:

  1. players.module

  2. players.service

  3. players.controller

  4. Creates files.


-PlayersService


import { Injectable } from '@nestjs/common';

@Injectable()
export class PlayersService {
private players = [
{ id: 1, name: 'Lionel Messi' },
{ id: 2, name: 'Cristiano Ronaldo' },
];

getPlayers() {
return this.players;
}
}
  • This service returns the player list.

-PlayersController


import { Controller, Get } from '@nestjs/common';
import { PlayersService } from './players.service';

@Controller('players')
export class PlayersController {
constructor(private readonly playersService: PlayersService) {}

@Get()
getPlayers() {
return this.playersService.getPlayers();
}
}
  • Controller receives the service via DI.

-PlayersModule


import { Module } from '@nestjs/common';
import { PlayersService } from './players.service';
import { PlayersController } from './players.controller';

@Module({
controllers: [PlayersController],
providers: [PlayersService],
})
export class PlayersModule {}
  • Module defines the provider and controller relationship.

Application Flow

  1. The request comes to /players.

  2. Controller works.

  3. Service is called.

  4. Data is returned.

  5. Decorator Logic


  • Decorators add metadata to classes.

function exampleDecorator(constructor: Function) {
console.log("Decorator çalıştı");
}

@exampleDecorator
class Example {}
  • Decorator runs before the class is created.

Important NestJS Decorators

1. Injectable() Specifies that a class will be managed by the DI system.

2. @Module() Defines the application structure.

3. @Controller() Specifies classes that handle HTTP requests.


Common Error: Lack of Provider


@Module({
controllers: [PlayersController],
providers: [],
})
export class PlayersModule {}

  • This structure produces errors. Because PlayersService has not been added as a provider.

Frequently Asked Questions

  1. Why is DI important? It ensures that the code is testable and maintainable.

  2. Is NestJS DI mandatory? Yes, it is the basis of architecture.

  3. What is a Provider? It is injectable class.

  4. Does the controller work without service? No, business logic must be in services.

  5. What is IoC container? It is the central structure that manages dependencies.


Result

In this guide, you learned the NestJS Dependency Injection logic in detail. Thanks to DI and IoC, you can develop more modular and scalable applications. This architecture forms the basis of large NestJS projects.

If you want, you can immediately test this structure on the GenixNode infrastructure.