Dependency Injection
Use NestJS 11's DI container for scopes, custom providers, and testable service wiring.
Search across all documentation pages
Use NestJS 11's DI container for scopes, custom providers, and testable service wiring.
Quick-reference recipe card - copy-paste ready.
import { Module, Injectable, Inject } from "@nestjs/common";
@Injectable()
export class UsersRepository {
findById(id: string) { return { id, name: "Ada" }; }
}
@Injectable()
export class UsersService {
constructor(private readonly repo: UsersRepository) {}
getUser(id: string) {
return this.repo.findById(id);
}
}
@Module({
providers: [UsersRepository, UsersService],
exports: [UsersService],
})
export class UsersModule {}When to reach for this: Any NestJS service that depends on another service, repository, or external client.
import { Module, Injectable, Inject } from "@nestjs/common";
import { Test } from "@nestjs/testing";
// Interface token for swappable implementations
export const EMAIL_SENDER = Symbol("EMAIL_SENDER");
export interface EmailSender {
send(to: string, subject: string): Promise<void>;
}
@Injectable()
export class SmtpEmailSender implements EmailSender {
async send(to: string, subject: string) {
console.log(`Sending to ${to}: ${subject}`);
}
}
@Injectable()
export class UsersService {
constructor(
@Inject(EMAIL_SENDER) private readonly email: EmailSender,
) {}
async register(email: string) {
await this.email.send(email, "Welcome!");
return { email };
}
}
@Module({
providers: [
UsersService,
{ provide: EMAIL_SENDER, useClass: SmtpEmailSender },
],
})
export class UsersModule {}
// Test override
const testModule = await Test.createTestingModule({
imports: [UsersModule],
})
.overrideProvider(EMAIL_SENDER)
.useValue({ send: async () => {} })
.compile();What this demonstrates:
SymboluseClass for interface-to-implementation bindingoverrideProvider for test doubles@Injectable() registers a class as a provider| Scope | Lifetime | Use for |
|---|---|---|
DEFAULT (singleton) | One instance per app | Services, repositories |
REQUEST | One per HTTP request | Request-scoped user context |
TRANSIENT | New instance per injection | Stateless helpers (rare) |
@Injectable({ scope: Scope.REQUEST })
export class RequestContextService {
userId?: string;
}| Pattern | Syntax | Use for |
|---|---|---|
useClass | { provide: TOKEN, useClass: Impl } | Interface binding |
useValue | { provide: TOKEN, useValue: obj } | Config, mocks |
useFactory | { provide: TOKEN, useFactory: fn, inject: [...] } | Async setup |
useExisting | { provide: TOKEN, useExisting: OtherToken } | Aliasing |
forwardRef(() => B) or refactor shared logic to a third service.ModuleRef or make the consumer request-scoped too.exports - service not available in importing module. Fix: add to exports array.new Service() - bypasses DI and testability. Fix: always inject via constructor.overrideProvider or useValue mock.| Alternative | Use When | Don't Use When |
|---|---|---|
| Manual DI (constructor params) | Simple Fastify/Express app | NestJS project (use built-in DI) |
| tsyringe | DI without NestJS framework | Already on NestJS |
| Factory functions | Lightweight services | Complex dependency graphs |
| ModuleRef.get() | Dynamic provider resolution | Normal constructor injection works |
Import ConfigModule.forRoot({ isGlobal: true }) and inject ConfigService in any provider.
Use @Inject(REQUEST) with request-scoped provider, or pass data from controller to service method (simpler).
Add to providers and exports in the providing module. Import that module wherever needed.
Delays resolution of a circular dependency. Use sparingly; refactoring is usually better.
useFactory with onModuleDestroy cleanup, or use @nestjs/typeorm / PrismaService wrapper.
Minimal at runtime (singleton resolution once). Request scope adds per-request instantiation cost.
Test.createTestingModule({ controllers: [X], providers: [{ provide: Y, useValue: mock }] }).compile().
Not idiomatically in NestJS. Decorators are the framework's core mechanism.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 18, 2026