CodePark/ questions / Providers & dependency injection
START PRACTICINGPRACTICE
Backend question · NestJS › Providers & dependency injection

Explain Nest's three injection scopes and the cost of using request scope.

@Injectable({ scope: Scope.REQUEST })
export class TenantContext {
  constructor(@Inject(REQUEST) private req: Request) {}
}

Nest has three injection scopes:

  • DEFAULT: one shared instance for the whole app, created at bootstrap. This is the recommended choice.
  • REQUEST: a new instance for each incoming request. Nest throws it away after the request finishes. You can inject the request object with the REQUEST token.
  • TRANSIENT: every consumer that injects the provider gets its own instance.

The cost of request scope: it bubbles up the injection chain. If a controller depends on a request-scoped service, the controller also becomes request-scoped. So does everything in between. Nest then creates all those objects on every request. This slows the app down and creates more memory work for the garbage collector.

Also, lifecycle hooks (like onModuleInit) are not called for request-scoped providers.

When you can, pass request data explicitly instead, or use AsyncLocalStorage.

  • DEFAULT scope is a singleton, and it is the recommended choice.
  • REQUEST scope creates a new instance per request and can inject REQUEST.
  • TRANSIENT scope creates a new instance per consumer.
  • Request scope bubbles up to everything that depends on it.
  • Creating instances on every request costs performance.