NestJS — Enterprise Node.js

Asynchronous Providers & Injection Scopes

18 min Lesson 52 of 80

Asynchronous Providers & Injection Scopes

Some providers cannot be built synchronously: database clients need connection strings, secrets may come from a vault, and SDKs might require async initialization. NestJS supports async factories and also lets you choose singleton, request, or transient provider lifetimes.

Core idea

This feature is about controlling how the application is organized and how it behaves at runtime. These are the points a developer should understand before using it in a real project:

  • useFactory can be async; Nest waits for the promise before the provider becomes injectable.
  • inject lists the dependencies passed into the factory in order.
  • Singleton scope is the default and is usually correct for services, repositories, clients, and caches.
  • Request scope creates a new instance per request and should be used carefully because it increases allocation cost and can bubble through dependencies.
  • Transient scope creates a new instance for each injection site and is useful for lightweight helper objects with local state.

Practical example

The following example shows the idea in a practical NestJS project. The goal is not to memorize the snippet, but to understand where it belongs in the architecture:

const RedisClientProvider = { provide: REDIS_CLIENT, inject: [ConfigService], useFactory: async (config: ConfigService) => { const client = createClient({ url: config.getOrThrow('REDIS_URL') }); await client.connect(); return client; }, }; @Injectable({ scope: Scope.REQUEST }) export class RequestAuditContext { readonly id = randomUUID(); }
Design note: Async providers are excellent for infrastructure clients. Request scope is not a replacement for passing explicit user or tenant data; use it only when a true per-request object makes the design simpler.

Production checklist

  • Validate configuration before creating async infrastructure providers.
  • Close clients in lifecycle hooks when the application shuts down.
  • Benchmark request-scoped providers before using them on hot paths.
  • Keep transient providers small and free of expensive startup work.
Rule of thumb: If the feature makes boundaries clearer and tests easier, it is probably the right choice. If it hides dependencies or makes tracing harder, redesign.

Summary

This lesson covers an advanced NestJS area that matters when building enterprise applications. Focus on clear boundaries, testable behavior, and choosing the right tool for the context instead of using every feature everywhere.