Custom Providers
Use useValue, useClass, and useFactory to control exactly how a provider is created.
Syntax
{ provide: TOKEN, useValue | useClass | useFactory }The shorthand providers: [UsersService] is the common case. Sometimes you need more control over how an instance is produced. Nest offers custom provider syntax.
The three forms
- useClass - provide a different class for a token, useful for swapping implementations.
- useValue - provide a ready-made object or constant, great for config or mocks.
- useFactory - run a function to build the instance, optionally injecting other providers.
Each custom provider has a provide token (often a class or a string) that consumers request.
Example
import { Module } from '@nestjs/common';
const API_KEY = 'API_KEY';
@Module({
providers: [
// useValue: a constant
{ provide: API_KEY, useValue: 'secret-123' },
// useFactory: build with logic
{
provide: 'CONFIG',
useFactory: () => ({ env: process.env.NODE_ENV ?? 'dev' }),
},
],
})
export class CoreModule {}When to use it
- A developer uses useValue to inject a pre-configured third-party client (e.g., an Axios instance) under a custom token.
- A team uses useFactory with async to create a database connection provider that awaits the connection before the app boots.
- An architect uses useClass to swap a concrete implementation for an environment-specific alternative (e.g., MockEmailService in tests, SmtpEmailService in production).
More examples
useValue custom provider
Registers a plain object under a string token using useValue so it can be injected with @Inject("APP_CONFIG").
import { Module } from '@nestjs/common';
const configProvider = {
provide: 'APP_CONFIG',
useValue: { apiUrl: 'https://api.example.com', timeout: 5000 },
};
@Module({ providers: [configProvider] })
export class AppModule {}useFactory async provider
Uses useFactory with inject to build an async provider that resolves its dependencies and performs async setup before the app starts.
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
@Module({
providers: [
{
provide: 'DB_CONNECTION',
inject: [ConfigService],
useFactory: async (cfg: ConfigService) => {
const url = cfg.get('DATABASE_URL');
return connectToDatabase(url); // async setup
},
},
],
})
export class DatabaseModule {}useClass environment swap
Swaps the real MailService for a MockMailService in test environments using useClass without changing any injection sites.
import { Module } from '@nestjs/common';
import { MailService } from './mail.service';
import { MockMailService } from './mock-mail.service';
@Module({
providers: [
{
provide: MailService,
useClass: process.env.NODE_ENV === 'test'
? MockMailService
: MailService,
},
],
})
export class MailModule {}
Discussion