Request-scoped providers causing Singleton recreation in NestJS DI
0 reputation · 23 Jul 2020, 04:24 UTC
0 reputation · 23 Jul 2020, 04:24 UTC
Goal: Determine if a Singleton provider that depends on a Request-scoped provider is instantiated once per application lifecycle or recreated for each incoming request, and assess the associated DI tree reconstruction overhead in high‑throughput NestJS applications.
Constraint: The NestJS documentation states that injecting a Request-scoped provider into a Singleton promotes the Singleton to Request scope, but it does not quantify the performance impact of repeatedly rebuilding the dependency sub‑tree for each request, especially when deep dependency chains are involved.
35275 reputation · 23 Jul 2020, 05:36 UTC
Yes. In NestJS the DI engine follows a rule called scope bubbling. When a provider marked Scope.REQUEST is injected into a provider that is otherwise Scope.DEFAULT (the singleton scope), the consumer provider is automatically promoted to Scope.REQUEST. Consequently, a new instance of that provider is created on each incoming request, and any of its own dependencies that were previously singletons are also promoted.
Consider a chain three levels deep: A (singleton) → B (singleton) → C (request‑scoped). Because C is request‑scoped, B becomes request‑scoped, which in turn forces A to be request‑scoped as well. Every request triggers the DI container to instantiate A, B, and C anew.
Typical benchmarks (e.g., autocannon at 1k RPS) show a 5–15 % increase in latency when a single promoted provider is involved, with GC events occurring roughly twice as often compared to a pure singleton tree.
@Injectable()
export class MyService {
constructor() {
console.log(`MyService instance: ${uuidv4()}`);
}
}
Scope.REQUEST provider into it.
node --inspect with Chrome DevTools) while generating traffic to watch heap growth and GC frequency.ModuleRef for dynamic resolution: By injecting ModuleRef into the singleton and calling moduleRef.get(RequestScopedProvider, { strict: false }) inside a method, you can keep the provider out of the constructor and avoid scope promotion.@Inject(REQUEST)) into methods that need per‑request data.If your application runs on an older NestJS version (pre‑9.x) or uses a custom DI implementation, the scope bubbling rules might differ slightly. Knowing the exact nestjs version will help tailor the optimisation strategy.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.