nestjs-dependency-injection
Use when nestJS dependency injection with providers, modules, and decorators. Use when building modular NestJS applications.
What this skill does
# NestJS Dependency Injection
Master NestJS dependency injection for building modular, testable
Node.js applications with proper service architecture, provider
patterns, and module organization.
## Table of Contents
- [Provider Patterns](#provider-patterns)
- [Module System](#module-system)
- [Injection Scopes](#injection-scopes)
- [Advanced Patterns](#advanced-patterns)
- [Best Practices](#best-practices)
- [Common Pitfalls](#common-pitfalls)
- [Resources](#resources)
## Provider Patterns
### Class Providers (Standard Pattern)
```typescript
import { Injectable } from '@nestjs/common';
@Injectable()
export class UserService {
private users: User[] = [];
findAll(): User[] {
return this.users;
}
findById(id: string): User | undefined {
return this.users.find(user => user.id === id);
}
create(user: User): User {
this.users.push(user);
return user;
}
}
// Module registration
@Module({
providers: [UserService],
exports: [UserService],
})
export class UserModule {}
```
### Value Providers
```typescript
import { Module } from '@nestjs/common';
// Simple value provider
const DATABASE_CONNECTION = {
provide: 'DATABASE_CONNECTION',
useValue: {
host: 'localhost',
port: 5432,
database: 'mydb',
},
};
// Configuration value provider
const APP_CONFIG = {
provide: 'APP_CONFIG',
useValue: {
apiUrl: process.env.API_URL,
timeout: 5000,
retries: 3,
},
};
@Module({
providers: [DATABASE_CONNECTION, APP_CONFIG],
exports: [DATABASE_CONNECTION, APP_CONFIG],
})
export class ConfigModule {}
// Usage in service
@Injectable()
export class ApiService {
constructor(
@Inject('APP_CONFIG') private config: AppConfig,
) {}
async fetchData(): Promise<any> {
const response = await fetch(this.config.apiUrl, {
timeout: this.config.timeout,
});
return response.json();
}
}
```
### Factory Providers
```typescript
import { Injectable, Module } from '@nestjs/common';
// Simple factory provider
const CONNECTION_FACTORY = {
provide: 'DATABASE_CONNECTION',
useFactory: () => {
return createConnection({
type: 'postgres',
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT),
database: process.env.DB_NAME,
});
},
};
// Factory with dependencies
const CACHE_MANAGER = {
provide: 'CACHE_MANAGER',
useFactory: (config: ConfigService) => {
return createCacheManager({
store: config.get('CACHE_STORE'),
ttl: config.get('CACHE_TTL'),
max: config.get('CACHE_MAX_ITEMS'),
});
},
inject: [ConfigService],
};
@Module({
providers: [
ConfigService,
CONNECTION_FACTORY,
CACHE_MANAGER,
],
exports: ['DATABASE_CONNECTION', 'CACHE_MANAGER'],
})
export class DatabaseModule {}
```
### Async Providers with useFactory
```typescript
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
const DATABASE_PROVIDER = {
provide: 'DATABASE_CONNECTION',
useFactory: async (config: ConfigService) => {
const connection = await createConnection({
type: 'postgres',
host: config.get('DB_HOST'),
port: config.get('DB_PORT'),
username: config.get('DB_USER'),
password: config.get('DB_PASSWORD'),
database: config.get('DB_NAME'),
});
await connection.runMigrations();
return connection;
},
inject: [ConfigService],
};
const REDIS_PROVIDER = {
provide: 'REDIS_CLIENT',
useFactory: async (config: ConfigService) => {
const client = createClient({
url: config.get('REDIS_URL'),
});
await client.connect();
client.on('error', (err) => {
console.error('Redis error:', err);
});
return client;
},
inject: [ConfigService],
};
@Module({
providers: [DATABASE_PROVIDER, REDIS_PROVIDER],
exports: ['DATABASE_CONNECTION', 'REDIS_CLIENT'],
})
export class DataModule {}
```
### Token-Based Injection with String Tokens
```typescript
import { Inject, Injectable, Module } from '@nestjs/common';
// Define string tokens as constants
export const LOGGER_TOKEN = 'LOGGER';
export const METRICS_TOKEN = 'METRICS';
export const API_CLIENT_TOKEN = 'API_CLIENT';
// Provider definitions
const LOGGER_PROVIDER = {
provide: LOGGER_TOKEN,
useFactory: () => {
return createLogger({
level: process.env.LOG_LEVEL || 'info',
format: 'json',
});
},
};
const METRICS_PROVIDER = {
provide: METRICS_TOKEN,
useValue: createMetricsClient(),
};
@Module({
providers: [LOGGER_PROVIDER, METRICS_PROVIDER],
exports: [LOGGER_TOKEN, METRICS_TOKEN],
})
export class ObservabilityModule {}
// Usage in service
@Injectable()
export class UserService {
constructor(
@Inject(LOGGER_TOKEN) private logger: Logger,
@Inject(METRICS_TOKEN) private metrics: MetricsClient,
) {}
async createUser(data: CreateUserDto): Promise<User> {
this.logger.info('Creating user', { email: data.email });
this.metrics.increment('user.created');
const user = await this.repository.create(data);
return user;
}
}
```
### Token-Based Injection with Symbol Tokens
```typescript
import { Inject, Injectable, Module } from '@nestjs/common';
// Define symbol tokens for better type safety
export const DATABASE_CONNECTION = Symbol('DATABASE_CONNECTION');
export const CACHE_MANAGER = Symbol('CACHE_MANAGER');
export const EVENT_BUS = Symbol('EVENT_BUS');
// Provider with symbol token
const DB_PROVIDER = {
provide: DATABASE_CONNECTION,
useFactory: async () => {
return await createDatabaseConnection();
},
};
const CACHE_PROVIDER = {
provide: CACHE_MANAGER,
useClass: RedisCacheManager,
};
@Module({
providers: [DB_PROVIDER, CACHE_PROVIDER],
exports: [DATABASE_CONNECTION, CACHE_MANAGER],
})
export class InfrastructureModule {}
// Usage with symbol tokens
@Injectable()
export class ProductService {
constructor(
@Inject(DATABASE_CONNECTION) private db: Connection,
@Inject(CACHE_MANAGER) private cache: CacheManager,
) {}
async findById(id: string): Promise<Product> {
const cached = await this.cache.get(`product:${id}`);
if (cached) return cached;
const product = await this.db
.getRepository(Product)
.findOne({ where: { id } });
await this.cache.set(`product:${id}`, product, 3600);
return product;
}
}
```
### Optional Dependencies with @Optional()
```typescript
import { Injectable, Optional, Inject } from '@nestjs/common';
@Injectable()
export class NotificationService {
constructor(
@Optional()
@Inject('EMAIL_SERVICE')
private emailService?: EmailService,
@Optional()
@Inject('SMS_SERVICE')
private smsService?: SmsService,
) {}
async notify(user: User, message: string): Promise<void> {
// Gracefully handle missing optional dependencies
if (this.emailService) {
await this.emailService.send(user.email, message);
}
if (this.smsService && user.phone) {
await this.smsService.send(user.phone, message);
}
// Always have a fallback notification method
await this.logNotification(user, message);
}
private async logNotification(
user: User,
message: string,
): Promise<void> {
console.log(`Notification for ${user.id}: ${message}`);
}
}
// Module with optional providers
@Module({
providers: [
NotificationService,
// EMAIL_SERVICE might not be registered
// SMS_SERVICE might not be registered
],
exports: [NotificationService],
})
export class NotificationModule {}
```
### Property-Based Injection
```typescript
import { Injectable, Inject } from '@nestjs/common';
// Property-based injection (less preferred)
@Injectable()
export class PaymentService {
@Inject('PAYMENT_GATEWAY')
private paymentGateway: PaymentGateway;
@Inject('FRAUD_DETECTOR')
private fraudDetector: FraudDetector;
async processPayment(
amount: number,
card: CardDetails,
): Promise<PaymentResult> {
const isFraudulent = await this.fraudDetector.check(cardRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.