Under The Hood
backend nestjs NestJS 10+ (on top of TypeScript/Express)

NestJS dependency injection container

Last updated
Prerequisites:
TypeScript decorators basics
NestJS modules and providers
  • nestjs
  • dependency-injection
  • container
  • typescript
  • reflect-metadata
  • decorators

Read at your depth

The practical view

In NestJS you mark a service with @Injectable(), list it in a module's providers, and inject it via a constructor parameter: constructor(private readonly usersService: UsersService) {}. Nest resolves the graph at bootstrap: it instantiates the provider (and all its transitive dependencies), caches it per the provider scope (DEFAULT = singleton per application, REQUEST = per request, TRANSIENT = per injection), and injects it where requested. Injection happens via the TypeScript design:paramtypes metadata that the compiler emits when decorators are present (reflect-metadata + emitDecoratorMetadata).

Legacy vs modern

Manual service wiring vs Nest DI container

Hand-constructed services tangle creation order and make swaps invasive; the container resolves the graph, applies scope, and enables clean test substitution.

before → after
Manual wiring
const repo = new UserRepository(db);
const svc = new UserService(repo);
const ctrl = new UserController(svc);
Nest DI
@Injectable()
export class UserService {
  constructor(private readonly repo: UserRepository) {}
}

Interview gotchas

Context

This is the core 'explain the magic' question — the interviewer wants the reflect-metadata + design:paramtypes mechanism, not just 'decorators'.

The mechanical answer

TypeScript emits metadata when decorators and emitDecoratorMetadata are enabled: for a class with a decorator, the compiler writes the constructor parameter types into a design:paramtypes metadata key on the class. Nest's runtime reads that metadata with reflect-metadata (Reflect.getMetadata) to discover the injected tokens. Because the metadata contains the type references only for class-based types, string/abstract/symbol tokens need @Inject(Token) to be discoverable — there is no design-time type for them. The @Injectable() decorator itself is the marker that makes Nest scan this class and read its metadata.

Trap

The naive answer is 'TypeScript types are available at runtime'. They are not — the metadata is only emitted for decorated classes and only for parameter types that are actual runtime references (classes). Candidates who say 'Nest uses the types from the constructor signature' miss that emitDecoratorMetadata is what makes it possible and that interface-based injection fails without @Inject. Mentioning the exact metadata key (design:paramtypes) is the differentiator.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.