Skip to content

NestJS Custom Providers

Not every provider is a simple class listed by name. Custom providers let you bind tokens to values, factories, and alternate classes—essential for config, mocking, and interfaces.

Provider Recipes

Nest supports several provider shapes: useClass (alias a token to a class), useValue (provide a constant), useFactory (compute a value with injected deps), and useExisting (create an alias). Tokens can be classes, strings, or symbols.

{
  provide: 'API_KEY',
  useValue: process.env.API_KEY,
}

{
  provide: PaymentsClient,
  useFactory: (config: ConfigService) => new PaymentsClient(config.get('PAYMENTS_KEY')),
  inject: [ConfigService],
}

Factories run inside the DI container, so they can inject ConfigService or other providers before constructing the value.

Injecting a Custom Token

constructor(@Inject('API_KEY') private apiKey: string) {}
  • Class tokens inject without @Inject; string/symbol tokens require @Inject(token).
  • useFactory can be async; Nest awaits it during bootstrap.
  • Custom providers are listed in the module providers array like normal classes.
  • Export custom providers if other modules need them.

Custom Provider Cheatsheet

Common provider object shapes.

Shape When to Use
useClass Swap interface token for implementation
useValue Constants, mocks, config objects
useFactory Construct with injected dependencies
useExisting Alias one provider to another token
Scope.REQUEST Per-request instance when needed

Interface Tokens

TypeScript interfaces disappear at runtime, so use an abstract class or a string/symbol token for interface-based injection.

export const HASHING_SERVICE = Symbol('HASHING_SERVICE');
{ provide: HASHING_SERVICE, useClass: BcryptHashingService }

Custom Providers in Tests

useValue: mockService in TestingModule is the fastest way to stub dependencies without spinning real infrastructure.

Common Mistakes

  • Forgetting @Inject('TOKEN') for non-class tokens.
  • Omitting inject: [...] on a factory that needs dependencies.
  • Using useValue for something that should be constructed per request.
  • Not exporting a custom provider that other modules try to inject.

Key Takeaways

  • Custom providers bind tokens to values, classes, or factories.
  • String/symbol tokens require @Inject.
  • Factories enable config-driven construction during bootstrap.
  • Tests heavily rely on useValue mocks.

Pro Tip

Prefer Symbol('NAME') tokens over magic strings for shared libraries to avoid accidental collisions across packages.