Dependency Injection
Declare a dependency in a constructor and Nest's container supplies the instance automatically.
constructor(private readonly service: MyService) {}Dependency injection (DI) is the heart of Nest. Rather than build its own dependencies, a class lists them as constructor parameters and Nest provides them.
Constructor injection
Add a parameter typed as the provider you need, marked private readonly. Nest looks up that type in its container and passes the existing instance.
This keeps classes loosely coupled and makes them easy to test - in a test you simply pass a fake service to the constructor.
Example
import { Controller, Get } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
// Nest injects the UsersService instance here
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
}When to use it
- A developer declares CatsService in a controller constructor and Nest automatically creates and injects the singleton instance.
- A team unit-tests a controller by providing a mock service through the DI container without touching the controller code.
- An architect uses constructor injection to make all dependencies explicit and discoverable, improving code readability and testability.
More examples
Constructor injection in controller
The standard constructor injection pattern β Nest reads the TypeScript type metadata and supplies the correct instance.
import { Controller, Get } from '@nestjs/common';
import { CatsService } from './cats.service';
@Controller('cats')
export class CatsController {
// Nest resolves and injects CatsService automatically
constructor(private readonly catsService: CatsService) {}
@Get()
findAll() {
return this.catsService.findAll();
}
}Service injecting another service
Demonstrates the DI chain: UsersService depends on UsersRepository, and Nest resolves the entire tree at startup.
import { Injectable } from '@nestjs/common';
import { UsersRepository } from './users.repository';
@Injectable()
export class UsersService {
constructor(private readonly repo: UsersRepository) {}
findOne(id: number) {
return this.repo.findById(id);
}
}Mocking provider in unit test
Shows how the DI container lets you swap a real service with a mock in tests by using the same token.
import { Test } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
const mockCatsService = { findAll: jest.fn(() => ['cat1']) };
const module = await Test.createTestingModule({
controllers: [CatsController],
providers: [{ provide: CatsService, useValue: mockCatsService }],
}).compile();
const controller = module.get(CatsController);
Discussion