NestJS Core Knowledge

SkillAI & models

NestJS enterprise Node.js framework. Covers modules, controllers, services, guards, and dependency injection. Use when building scalable Node.js applications.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the NestJS Core Knowledge skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/backend-frameworks/nestjs/SKILL.md and read by ahel’s review.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: nestjs for comprehensive documentation.

Module Structure

// users.module.ts
@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

Controller

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll(): Promise<User[]> {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string): Promise<User> {
    return this.usersService.findOne(id);
  }

  @Post()
  @HttpCode(201)
  create(@Body() createUserDto: CreateUserDto): Promise<User> {
    return this.usersService.create(createUserDto);
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() dto: UpdateUserDto) {
    return this.usersService.update(id, dto);
  }

  @Delete(':id')
  @HttpCode(204)
  remove(@Param('id') id: string) {
    return this.usersService.remove(id);
  }
}

Service

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>,
  ) {}

  findAll(): Promise<User[]> {
    return this.usersRepository.find();
  }

  findOne(id: string): Promise<User | null> {
    return this.usersRepository.findOneBy({ id });
  }
}

Key Decorators

DecoratorPurpose
@ModuleDefine module
@ControllerDefine controller
@InjectableMark as provider
@Get/@Post/@Put/@DeleteHTTP methods
@Body/@Param/@QueryRequest data
@UseGuardsApply guards
@UsePipesApply pipes

Production Readiness

Security Configuration

// main.ts - Security setup
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import helmet from 'helmet';
import * as compression from 'compression';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Security headers
  app.use(helmet());

  // CORS configuration
  app.enableCors({
    origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
    credentials: true,
  });

  // Global validation pipe
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,           // Strip non-whitelisted properties
    forbidNonWhitelisted: true, // Throw on non-whitelisted
    transform: true,            // Auto-transform payloads
  }));

  // Response compression
  app.use(compression());

  // Rate limiting (with @nestjs/throttler)
  // Configured in AppModule

  await app.listen(process.env.PORT || 3000);
}
// Rate limiting module
import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';

@Module({
  imports: [
    ThrottlerModule.forRoot([{
      ttl: 60000,    // 1 minute
      limit: 100,    // 100 requests per minute
    }]),
  ],
  providers: [{
    provide: APP_GUARD,
    useClass: ThrottlerGuard,
  }],
})
export class AppModule {}

Health Checks

// health.controller.ts
import { Controller, Get } from '@nestjs/common';
import { HealthCheck, HealthCheckService, HttpHealthIndicator, TypeOrmHealthIndicator } from '@nestjs/terminus';

@Controller('health')
export class HealthController {
  constructor(
    private health: HealthCheckService,
    private http: HttpHealthIndicator,
    private db: TypeOrmHealthIndicator,
  ) {}

  @Get()
  @HealthCheck()
  check() {
    return this.health.check([
      () => this.db.pingCheck('database'),
    ]);
  }

  @Get('ready')
  @HealthCheck()
  readiness() {
    return this.health.check([
      () => this.db.pingCheck('database'),
      () => this.http.pingCheck('external-api', 'https://api.example.com/health'),
    ]);
  }
}

Logging

// Structured logging with Pino
import { LoggerModule } from 'nestjs-pino';

@Module({
  imports: [
    LoggerModule.forRoot({
      pinoHttp: {
        level: process.env.LOG_LEVEL || 'info',
        transport: process.env.NODE_ENV !== 'production'
          ? { target: 'pino-pretty' }
          : undefined,
        redact: ['req.headers.authorization', 'req.body.password'],
      },
    }),
  ],
})
export class AppModule {}

Monitoring Metrics

MetricAlert Threshold
Request latency p99> 500ms
Error rate (5xx)> 1%
Memory usage> 80%
CPU usage> 70%
Active connections> 1000
Request queue depth> 100

Exception Handling

// Global exception filter
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  constructor(private readonly logger: Logger) {}

  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    const status = exception instanceof HttpException
      ? exception.getStatus()
      : HttpStatus.INTERNAL_SERVER_ERROR;

    const message = exception instanceof HttpException
      ? exception.getResponse()
      : 'Internal server error';

    this.logger.error({
      statusCode: status,
      path: request.url,
      method: request.method,
      message,
      stack: exception instanceof Error ? exception.stack : undefined,
    });

    response.status(status).json({
      statusCode: status,
      message: status === 500 ? 'Internal server error' : message,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}

Checklist

  • Helmet security headers enabled
  • CORS properly configured
  • Rate limiting implemented
  • Input validation with class-validator
  • Global exception filter
  • Health/readiness endpoints
  • Structured logging (no console.log)
  • Secrets via environment variables
  • HTTPS in production
  • Request timeout configured
  • Graceful shutdown handling

When NOT to Use This Skill

  • Minimalist APIs: Use Express for lightweight, unopinionated APIs
  • Maximum Performance: Use Fastify for high-throughput, low-latency requirements
  • Edge Runtimes: Use Hono for Cloudflare Workers, Vercel Edge, or Deno Deploy
  • Microservices Communication: Defer to kafka-expert or rabbitmq-expert for message brokers
  • Database Operations: Use prisma-expert or sql-expert for ORM/database specifics
  • WebSocket Implementation: Use dedicated WebSocket skill (coming soon)

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
Using console.log() for loggingNo structured logging, hard to queryUse nestjs-pino or Winston with structured logs
Circular dependencies between modulesCauses initialization failuresUse forwardRef() or redesign module boundaries
Business logic in controllersViolates SRP, hard to testMove logic to services, controllers orchestrate only
Not using DTOs for validationSecurity risk, inconsistent dataUse class-validator with DTOs for all inputs
Hardcoding config valuesNot portable, security riskUse @nestjs/config with env variables
Not implementing graceful shutdownData loss, incomplete requestsHandle SIGTERM, close connections properly
Mixing ORM logic with business logicTight coupling, hard to testUse repository pattern, inject repositories
Not using guards for authorizationSecurity vulnerabilitiesImplement guards for auth/authz checks

Quick Troubleshooting

IssueLikely CauseSolution
"Circular dependency detected"Module A imports B, B imports AUse forwardRef() or extract shared logic
"Cannot find module" in testsPath mapping not resolvedConfigure moduleNameMapper in Jest config
Guards not executingWrong order in app setupApply guards after pipes: app.useGlobalGuards()
DTOs not validatingValidationPipe not globalAdd app.useGlobalPipes(new ValidationPipe()) in main.ts
High memory usageMemory leaks in subscriptionsUse takeUntil() or unsubscribe in onModuleDestroy()
Slow startup timeToo many providers/importsLazy load modules, optimize dependency tree
404 for all routesControllers not registeredAdd controllers to module's controllers array
Middleware not executingIncorrect order or pathCheck middleware order, use forRoutes('*') for global

Reference Documentation

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
nestjs
Source
github.com/claude-dev-suite/claude-dev-suite