Loading skill
Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Cursor rules that block deprecated, phantom, or incorrect NestJS imports, decorators, providers, modules, and testing patterns.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-18 | ✗→✓ | ▲ Improved | 59% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-19 | ✓→✗ | ▼ Worse | 64% | 0% |
| case-07 | ✓→✗ | ▼ Worse | 73% | 0% |
| case-12 | ✓→✓ | = Same ✓ | 62% | 0% |
Cursor rules that block deprecated, phantom, or incorrect NestJS imports, decorators, providers, modules, and testing patterns.
Synced from https://github.com/PatrickJS/awesome-cursorrules/tree/main/rules/nestjs-anti-hallucination-cursorrules-prompt-file.mdc.
These rules OVERRIDE all other generation behavior. Check EVERY line of generated code against these rules.
❌ @nestjs/core/decorators — not a real export path
❌ @nestjs/swagger/decorators — import from @nestjs/swagger directly
❌ @nestjs/typeorm/repository — not a real export path
❌ @nestjs/passport/strategies — import from passport-jwt, passport-local, etc.
❌ @nestjs/bull/decorators — import from @nestjs/bullmq (bull is legacy)
❌ nestjs-redis — use @nestjs-modules/ioredis or ioredis directly
❌ @nestjs/cqrs/decorators — import from @nestjs/cqrs directly
❌ nestjs-config — use @nestjs/config (official)
❌ nestjs-pino/logger — import from nestjs-pino directlytypescript// ✅ Swagger import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; // ✅ TypeORM import { InjectRepository } from '@nestjs/typeorm'; import { Repository, DataSource } from 'typeorm'; // ✅ BullMQ (NOT Bull) import { InjectQueue, Processor, WorkerHost } from '@nestjs/bullmq'; // ✅ Config import { ConfigService, ConfigModule } from '@nestjs/config'; // ✅ Passport import { AuthGuard } from '@nestjs/passport'; import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt'; // ✅ CQRS import { CommandHandler, ICommandHandler, EventBus } from '@nestjs/cqrs';
typescript// ❌ DEPRECATED — removed in TypeORM 0.3+ const repo = getRepository(User); const user = await getConnection().getRepository(User).find(); // ✅ CORRECT — inject via constructor constructor( @InjectRepository(User) private readonly userRepo: Repository<User>, ) {}
typescript// ❌ OLD — @nestjs/bull with @Process decorator import { Process, Processor } from '@nestjs/bull'; @Processor('queue') class MyProcessor { @Process() async handle(job: Job) {} } // ✅ CURRENT — @nestjs/bullmq with WorkerHost import { Processor, WorkerHost } from '@nestjs/bullmq'; @Processor('queue') class MyProcessor extends WorkerHost { async process(job: Job): Promise<void> {} }
typescript// ❌ WRONG — Express req/res types in NestJS import { Request, Response } from 'express'; @Get() async findAll(@Req() req: Request, @Res() res: Response) { res.json(data); // Bypasses interceptors, serialization, exception filters } // ✅ CORRECT — Use NestJS decorators, return values @Get() async findAll(@Query() query: FindAllQueryDto): Promise<UserResponseDto[]> { return this.usersService.findAll(query); } // Only use @Res() when streaming files or SSE — add { passthrough: true } @Get('download') async download(@Res({ passthrough: true }) res: Response) { res.set('Content-Type', 'application/octet-stream'); return new StreamableFile(stream); }
typescript// ❌ WRONG — @Injectable() on a controller @Injectable() @Controller('users') export class UsersController {} // ❌ WRONG — @Controller() on a service @Controller() @Injectable() export class UsersService {} // ❌ WRONG — @Body() in a GET handler @Get() async findAll(@Body() body: any) {} // GET requests should not have a body // ❌ WRONG — Both @Param and @Query with same name @Get(':id') async findOne(@Param('id') paramId: string, @Query('id') queryId: string) {}
typescript// ❌ WRONG — Validation without enabling in main.ts // (AI often forgets this critical line) // main.ts MUST have: app.useGlobalPipes(new ValidationPipe({ whitelist: true, // Strip unknown properties forbidNonWhitelisted: true, // Throw on unknown properties transform: true, // Auto-transform payloads to DTO instances transformOptions: { enableImplicitConversion: true, }, })); // ❌ WRONG — Mixing validation decorators with wrong transform export class CreateUserDto { @IsString() name: string; @IsNumber() age: string; // Type mismatch! Decorator says number, type says string } // ✅ CORRECT — Types match decorators export class CreateUserDto { @IsString() @IsNotEmpty() name: string; @IsInt() @Min(0) age: number; }
typescript// ❌ WRONG — useFactory without async when awaiting TypeOrmModule.forRootAsync({ useFactory: (config: ConfigService) => ({ type: 'postgres', url: config.get('DATABASE_URL'), // Not awaited, no inject }), }) // ✅ CORRECT TypeOrmModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: async (config: ConfigService) => ({ type: 'postgres', url: config.getOrThrow<string>('DATABASE_URL'), autoLoadEntities: true, synchronize: false, // NEVER true in production }), })
anytypescript// ❌ BANNED catch (error: any) { ... } const data: any = await response.json(); private cache = new Map<string, any>(); // ✅ REQUIRED catch (error: unknown) { if (error instanceof DomainError) { ... } throw error; } const data = await response.json() as PaymentGatewayResponse; private cache = new Map<string, CachedSession>();
typescript// ❌ WRONG eventBus.emit('order.created', { order }); // ✅ CORRECT — Typed events export class OrderCreatedEvent { constructor( public readonly orderId: string, public readonly userId: string, public readonly totalAmount: number, public readonly occurredAt: Date = new Date(), ) {} } eventBus.emit(new OrderCreatedEvent(order.id, order.userId, order.total));
typescript// ❌ WRONG const port = process.env.PORT || 3000; const dbUrl = process.env.DATABASE_URL; // ✅ CORRECT const port = this.configService.getOrThrow<number>('app.port'); const dbUrl = this.configService.getOrThrow<string>('database.url');
typescript// ❌ synchronize: true in production config // ❌ DROP TABLE or TRUNCATE in migration files // ❌ Raw SQL without parameterized queries await this.dataSource.query(`SELECT * FROM users WHERE id = '${userId}'`); // SQL injection! // ✅ CORRECT await this.dataSource.query(`SELECT * FROM users WHERE id = $1`, [userId]);
Other measured skills in the registry, with their headline benchmark lift.