NestJS
NestJS provides a modular architecture with dependency injection, decorators for routing and validation, guards for auth, and interceptors for cross-cutting concerns.
Best use case
NestJS is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
NestJS provides a modular architecture with dependency injection, decorators for routing and validation, guards for auth, and interceptors for cross-cutting concerns.
Teams using NestJS should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/nestjs/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How NestJS Compares
| Feature / Agent | NestJS | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
NestJS provides a modular architecture with dependency injection, decorators for routing and validation, guards for auth, and interceptors for cross-cutting concerns.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# NestJS
NestJS provides a modular architecture with dependency injection, decorators for routing and validation, guards for auth, and interceptors for cross-cutting concerns.
## Installation
```bash
# Create new NestJS project
npm i -g @nestjs/cli
nest new my-api
cd my-api
npm i @nestjs/typeorm typeorm pg class-validator class-transformer
```
## Project Structure
```
# Standard NestJS project layout
src/
├── main.ts # Bootstrap
├── app.module.ts # Root module
├── articles/
│ ├── articles.module.ts # Feature module
│ ├── articles.controller.ts
│ ├── articles.service.ts
│ ├── entities/article.entity.ts
│ └── dto/
│ ├── create-article.dto.ts
│ └── update-article.dto.ts
├── auth/
│ ├── auth.module.ts
│ ├── auth.guard.ts
│ └── auth.service.ts
└── common/
├── filters/
└── interceptors/
```
## Module
```typescript
// src/articles/articles.module.ts — feature module
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArticlesController } from './articles.controller';
import { ArticlesService } from './articles.service';
import { Article } from './entities/article.entity';
@Module({
imports: [TypeOrmModule.forFeature([Article])],
controllers: [ArticlesController],
providers: [ArticlesService],
exports: [ArticlesService],
})
export class ArticlesModule {}
```
## Entity
```typescript
// src/articles/entities/article.entity.ts — TypeORM entity
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne } from 'typeorm';
import { User } from '../../users/entities/user.entity';
@Entity()
export class Article {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 200 })
title: string;
@Column('text')
body: string;
@ManyToOne(() => User, (user) => user.articles)
author: User;
@CreateDateColumn()
createdAt: Date;
}
```
## DTOs with Validation
```typescript
// src/articles/dto/create-article.dto.ts — validated DTO
import { IsString, IsNotEmpty, MaxLength } from 'class-validator';
export class CreateArticleDto {
@IsString()
@IsNotEmpty()
@MaxLength(200)
title: string;
@IsString()
@IsNotEmpty()
body: string;
}
```
## Controller
```typescript
// src/articles/articles.controller.ts — REST controller
import {
Controller, Get, Post, Body, Param, Delete,
ParseIntPipe, UseGuards, Query, HttpCode, HttpStatus,
} from '@nestjs/common';
import { ArticlesService } from './articles.service';
import { CreateArticleDto } from './dto/create-article.dto';
import { AuthGuard } from '../auth/auth.guard';
@Controller('articles')
export class ArticlesController {
constructor(private readonly articlesService: ArticlesService) {}
@Get()
findAll(@Query('page') page = 1, @Query('limit') limit = 20) {
return this.articlesService.findAll(+page, +limit);
}
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.articlesService.findOne(id);
}
@Post()
@UseGuards(AuthGuard)
@HttpCode(HttpStatus.CREATED)
create(@Body() dto: CreateArticleDto) {
return this.articlesService.create(dto);
}
@Delete(':id')
@UseGuards(AuthGuard)
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id', ParseIntPipe) id: number) {
return this.articlesService.remove(id);
}
}
```
## Service
```typescript
// src/articles/articles.service.ts — business logic with DI
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Article } from './entities/article.entity';
import { CreateArticleDto } from './dto/create-article.dto';
@Injectable()
export class ArticlesService {
constructor(
@InjectRepository(Article)
private readonly repo: Repository<Article>,
) {}
async findAll(page: number, limit: number) {
return this.repo.find({
skip: (page - 1) * limit,
take: limit,
order: { createdAt: 'DESC' },
relations: ['author'],
});
}
async findOne(id: number) {
const article = await this.repo.findOne({ where: { id }, relations: ['author'] });
if (!article) throw new NotFoundException(`Article #${id} not found`);
return article;
}
async create(dto: CreateArticleDto) {
const article = this.repo.create(dto);
return this.repo.save(article);
}
async remove(id: number) {
const result = await this.repo.delete(id);
if (result.affected === 0) throw new NotFoundException();
}
}
```
## Guards
```typescript
// src/auth/auth.guard.ts — JWT auth guard
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request>();
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) throw new UnauthorizedException();
try {
request['user'] = await this.jwtService.verifyAsync(token);
return true;
} catch {
throw new UnauthorizedException();
}
}
}
```
## App Module and Bootstrap
```typescript
// src/app.module.ts — root module with TypeORM config
import { Module, ValidationPipe } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArticlesModule } from './articles/articles.module';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: process.env.DB_HOST ?? 'localhost',
port: 5432,
database: process.env.DB_NAME ?? 'mydb',
username: process.env.DB_USER ?? 'postgres',
password: process.env.DB_PASSWORD ?? '',
autoLoadEntities: true,
synchronize: process.env.NODE_ENV !== 'production',
}),
ArticlesModule,
],
})
export class AppModule {}
```
```typescript
// src/main.ts — bootstrap with global pipes
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
app.enableCors();
await app.listen(3000);
}
bootstrap();
```
## Testing
```typescript
// src/articles/articles.service.spec.ts — unit test
import { Test } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { ArticlesService } from './articles.service';
import { Article } from './entities/article.entity';
describe('ArticlesService', () => {
let service: ArticlesService;
const mockRepo = { find: jest.fn().mockResolvedValue([]), create: jest.fn(), save: jest.fn() };
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
ArticlesService,
{ provide: getRepositoryToken(Article), useValue: mockRepo },
],
}).compile();
service = module.get(ArticlesService);
});
it('returns articles', async () => {
expect(await service.findAll(1, 20)).toEqual([]);
});
});
```
## Key Patterns
- One module per feature; import only what you need
- Use `ValidationPipe` with `whitelist: true` to strip unknown properties
- Use guards for auth, interceptors for response mapping, filters for exceptions
- Set `synchronize: false` in production — use TypeORM migrations instead
- Use `@nestjs/config` with `ConfigModule.forRoot()` for environment variablesRelated Skills
nestjs-module-generator
Nestjs Module Generator - Auto-activating skill for Backend Development. Triggers on: nestjs module generator, nestjs module generator Part of the Backend Development skill category.
nestjs-expert
Nest.js framework expert specializing in module architecture, dependency injection, middleware, guards, interceptors, testing with Jest/Supertest, TypeORM/Mongoose integration, and Passport.js authentication. Use PROACTIVELY for any Nest.js application issues including architecture decisions, testing strategies, performance optimization, or debugging complex dependency injection problems. If a specialized expert is a better fit, I will recommend switching and stop.
nestjs-transport
gRPC, RabbitMQ standards and Monorepo contracts. Use when implementing gRPC microservices, RabbitMQ messaging, or monorepo transport in NestJS. (triggers: main.ts, **/*.controller.ts, Transport.GRPC, Transport.RMQ, MicroserviceOptions)
nestjs-testing
Unit and E2E testing with Jest, mocking strategies, and database isolation. Use when writing NestJS unit tests, E2E tests with supertest, or mock providers. (triggers: **/*.spec.ts, test/**/*.e2e-spec.ts, Test.createTestingModule, supertest, jest, beforeEach)
nestjs-security
Authentication, RBAC, and Hardening standards. Use when implementing JWT auth, RBAC guards, or security hardening in NestJS. (triggers: **/*.guard.ts, **/*.strategy.ts, **/auth/**, Passport, JWT, AuthGuard, CSRF, Helmet)
nestjs-security-isolation
Standards for multi-tenant isolation and PostgreSQL Row Level Security. Use when enforcing tenant isolation or PostgreSQL RLS in NestJS multi-tenant apps. (triggers: src/modules/**, SECURITY.md, src/migrations/**, RLS, Row Level Security, childId, isolation, access policy)
nestjs-search
Elasticsearch integration and Sync patterns. Use when integrating Elasticsearch or implementing search index sync in NestJS. (triggers: **/*.service.ts, **/search/**, Elasticsearch, CQRS, Synchronization)
nestjs-scheduling
Distributed cron jobs and locking patterns. Use when implementing scheduled tasks or distributed locking patterns in NestJS. (triggers: **/*.service.ts, @Cron, CronExpression, ScheduleModule)
nestjs-observability
Structured logging (Pino) and Prometheus metrics. Use when adding structured logging with Pino or Prometheus metrics to NestJS services. (triggers: main.ts, **/*.module.ts, nestjs-pino, Prometheus, Logger, reqId)
nestjs-notification
Standards for Notification Types, Service Architecture, and FCM Integration. Use when building notification services or integrating FCM in NestJS. (triggers: notification.service.ts, notification.entity.ts, notification, push, fcm, alert, reminder)
nestjs-file-uploads
Secure file handling, Validation, and S3 streaming. Use when implementing secure file uploads, validation, or S3 streaming in NestJS. (triggers: **/*.controller.ts, FileInterceptor, Multer, S3, UploadedFile)
nestjs-error-handling
Global Exception Filters and standard error formats. Use when implementing global exception filters or standardizing error responses in NestJS. (triggers: **/*.filter.ts, main.ts, ExceptionFilter, Catch, HttpException)