From harness-claude
Organizes NestJS applications with cohesive feature modules, controlled exports, and composable dynamic configurations. Useful when structuring providers, avoiding circular dependencies, or building reusable configurable modules.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:nestjs-module-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Organize NestJS applications with cohesive feature modules, controlled exports, and composable dynamic configurations
Organize NestJS applications with cohesive feature modules, controlled exports, and composable dynamic configurations
UsersModule, OrdersModule, AuthModule). Group the controller, service, and repository for that domain inside it.providers array of the module that owns it. Only add it to exports when another module needs to inject it.@Global() sparingly: only for truly cross-cutting utilities (logging, config, event bus). Overuse destroys encapsulation.forRoot() / forFeature() static methods for modules that need external configuration:@Module({})
export class DatabaseModule {
static forRoot(options: DatabaseOptions): DynamicModule {
return {
module: DatabaseModule,
providers: [{ provide: DATABASE_OPTIONS, useValue: options }, DatabaseService],
exports: [DatabaseService],
global: true,
};
}
}
forFeature() for per-feature registration (e.g., registering Prisma models or TypeORM repositories for a specific module).AppModule thin — it should only import feature modules and global infrastructure modules, not declare providers directly.SharedModule.NestJS modules are the primary unit of application organization. They enforce explicit dependency declaration: a module cannot use a provider unless it either declares it internally or imports a module that exports it. This makes dependency graphs auditable and prevents accidental coupling.
Module anatomy:
@Module({
imports: [TypeOrmModule.forFeature([User])], // modules whose exports you need
controllers: [UsersController], // route handlers scoped to this module
providers: [UsersService, UsersRepository], // services, repos, guards, etc.
exports: [UsersService], // what other modules may inject
})
export class UsersModule {}
Dynamic modules solve the configuration problem. A static module cannot accept runtime configuration; forRoot() returns a DynamicModule object that NestJS treats identically to a static module but allows passing options:
// In AppModule:
DatabaseModule.forRoot({ url: process.env.DATABASE_URL });
Global modules (@Global()) register their exports into every module without requiring an explicit imports declaration. Use this for config, logging, and event buses — not for business-logic services where explicit imports communicate intent.
Shared modules are a common pattern for breaking circular dependencies. Extract the shared provider into its own module, export it, and import SharedModule from both dependents.
Trade-offs:
https://docs.nestjs.com/modules
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeGuides NestJS dependency injection using class, value, factory providers, modules, decorators, scopes, and best practices for modular Node.js apps.
Enforces NestJS best practices for modular architecture, dependency injection scoping, exception filters, class-validator DTO validation, and Drizzle ORM integration. Use when designing modules, providers, filters, DTOs, or ORM in NestJS apps.
Provides NestJS architecture patterns for building modular, production-grade TypeScript backends with validation, guards, interceptors, and config.