NestJS Patterns

SkillDev tools

NestJS best practices, module architecture, DTOs, Guards, Interceptors, and common patterns. Use when building or reviewing NestJS backend services.

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 Patterns skill

What this skill tells your AI

The instructions your AI receives, as published by sabahattink/antigravity-fullstack-hq in skills/nestjs-patterns/SKILL.md and read by ahel’s review.

Module Structure

src/modules/users/
├── users.module.ts
├── users.controller.ts
├── users.service.ts
├── dto/
│   ├── create-user.dto.ts
│   └── update-user.dto.ts
├── entities/
│   └── user.entity.ts
└── guards/
    └── user-owner.guard.ts

Key Patterns

Module Definition

@Module({
  imports: [PrismaModule],
  controllers: [UsersController],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

DTOs with Validation

import { IsEmail, IsString, MinLength } from 'class-validator'

export class CreateUserDto {
  @IsEmail()
  email: string

  @IsString()
  @MinLength(8)
  password: string
}

Service Pattern

@Injectable()
export class UsersService {
  constructor(private readonly prisma: PrismaService) {}

  async create(dto: CreateUserDto) {
    return this.prisma.user.create({ data: dto })
  }

  async findOne(id: string) {
    const user = await this.prisma.user.findUnique({ where: { id } })
    if (!user) throw new NotFoundException()
    return user
  }
}

Controller Pattern

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

  @Post()
  @HttpCode(HttpStatus.CREATED)
  create(@Body() dto: CreateUserDto) {
    return this.usersService.create(dto)
  }

  @Get(':id')
  @UseGuards(JwtAuthGuard)
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(id)
  }
}

Guards

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

@Injectable()
export class ResourceOwnerGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest()
    return request.user.id === request.params.id
  }
}

Custom Decorators

export const CurrentUser = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest()
    return data ? request.user?.[data] : request.user
  },
)

// Usage: @CurrentUser() user or @CurrentUser('id') id

Forbidden Patterns

  • Business logic in controllers
  • Returning sensitive data (passwords)
  • No validation on inputs
  • Hardcoded secrets
  • Skipping error handling

Signals

GitHub stars
30
Forks
9
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
nestjs-patterns-sabahattink
Source
github.com/sabahattink/antigravity-fullstack-hq