From harness-claude
Guides NestJS dependency injection with tokens, useClass/useValue/useFactory providers for swappable implementations, plain values, async init, and resolving 'Cannot resolve dependencies' errors.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Master NestJS DI container with tokens, useClass/useValue/useFactory providers
Guides NestJS dependency injection using class, value, factory providers, modules, decorators, scopes, and best practices for modular Node.js apps.
Implements Angular dependency injection using providers (useClass, useValue, useFactory), injectors, and services for modular, testable applications.
Organizes NestJS applications using feature modules, controlled exports, dynamic configurations with forRoot/forFeature. Useful for structuring new features, sharing providers without circular dependencies, and building reusable modules.
Share bugs, ideas, or general feedback.
Master NestJS DI container with tokens, useClass/useValue/useFactory providers
Standard provider (shorthand): providers: [MyService] — NestJS creates one singleton instance, injected by class type.
useClass — swap implementations:
providers: [
{ provide: MyService, useClass: process.env.NODE_ENV === 'test' ? MockMyService : MyService },
];
export const STRIPE_CLIENT = 'STRIPE_CLIENT';
providers: [
{ provide: STRIPE_CLIENT, useValue: new Stripe(process.env.STRIPE_KEY!) }
]
// inject with @Inject token
constructor(@Inject(STRIPE_CLIENT) private stripe: Stripe) {}
providers: [
{
provide: DATABASE_CONNECTION,
useFactory: async (config: ConfigService): Promise<DataSource> => {
const ds = new DataSource({ url: config.get('DATABASE_URL') });
await ds.initialize();
return ds;
},
inject: [ConfigService],
},
];
Symbol-based or class-based tokens over plain strings to avoid collisions:export const MAIL_OPTIONS = new InjectionToken<MailOptions>('MailOptions');
@Inject(TOKEN) when the token is not a class:constructor(@Inject(MAIL_OPTIONS) private options: MailOptions) {}
@Optional() when a provider may not be registered: constructor(@Optional() @Inject(CACHE) private cache?: Cache) {}.NestJS uses a hierarchical IoC container built on top of Reflect metadata. When you add a class to providers, the container reads its constructor parameter types via TypeScript's emitDecoratorMetadata and resolves each dependency recursively.
Token resolution: A provider token can be a class, a string, a Symbol, or an InjectionToken<T>. The container matches the provide key to the @Inject() token (or the constructor type for class providers). Mismatched tokens are the second most common DI error after missing exports.
Scopes and singleton behavior: Default (singleton) scope means useFactory runs once at app startup. REQUEST scope runs the factory (or constructor) per request — useful for per-request database connections or tenant-aware clients.
Testing: overrideProvider(MyService).useValue(mockService) in Test.createTestingModule() replaces any token with a mock without touching the module graph. This is the cleanest way to unit-test controllers and services.
ModuleRef.resolve() for dynamic resolution: When you need to resolve a provider at runtime (e.g., strategy pattern where the concrete implementation depends on runtime data), inject ModuleRef and call moduleRef.resolve(SomeService).
https://docs.nestjs.com/fundamentals/custom-providers