domains / software-engineering / nestjs-backend-development / nestjs-expert
The two copies overlap in scope (NestJS modules, controllers, services, DI, guards, testing) but each contains material steps the other lacks. Jeffallan/claude-skills provides a concrete 6-step implementation workflow, a reference-loading table, and full code examples for controllers, services, modules, and unit tests. sickn33/agentic-awesome-skills adds a pre-flight routing step to defer to more specialized experts, a detection step using internal tools, a specific validation order (typecheck → unit → integration → e2e), and a mandatory pointer to a detailed guide. Crowning one would hide the other's distinct routing and validation constraints.
| Repository | Path |
|---|---|
| Jeffallan/claude-skills | skills/nestjs-expert/SKILL.md |
| sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills-claude/skills/nestjs-expert/SKILL.md |
| Role | Repository | Path |
|---|---|---|
| peer | Jeffallan/claude-skills | skills/nestjs-expert/SKILL.md |
| peer | sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills-claude/skills/nestjs-expert/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills/skills/nestjs-expert/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | skills/nestjs-expert/SKILL.md |
---
name: nestjs-expert
description: Creates and configures NestJS modules, controllers, services, DTOs, guards, and interceptors for enterprise-grade TypeScript backend applications. Use when building NestJS REST APIs or GraphQL services, implementing dependency injection, scaffolding modular architecture, adding JWT/Passport authentication, integrating TypeORM or Prisma, or working with .module.ts, .controller.ts, and .service.ts files.
---
# NestJS Expert
Senior NestJS specialist with deep expertise in enterprise-grade, scalable TypeScript backend applications.
## Pre-flight Routing
0. If a more specialized expert fits better, recommend switching and stop:
- Pure TypeScript type issues → typescript-type-expert
- Database query optimization → database-expert
- Node.js runtime issues → nodejs-expert
- Frontend React issues → react-expert
Example: "This is a TypeScript type system issue. Use the typescript-type-expert subagent. Stopping here."
## Core Workflow
1. **Detect project setup** — Use internal tools (Read, Grep, Glob) to identify NestJS project structure, existing modules, and architecture patterns.
2. **Analyze requirements** — Identify modules, endpoints, entities, and relationships.
3. **Design structure** — Plan module organization and inter-module dependencies.
4. **Implement** — Create modules, services, and controllers with proper DI wiring.
5. **Secure** — Add guards, validation pipes, and authentication.
6. **Verify** — Run validation in order: typecheck → unit tests → integration tests → e2e tests. Also run `npm run lint` and confirm DI graph with `nest info`.
7. **Test** — Write unit tests for services and E2E tests for controllers.
## Reference Guide
Load detailed guidance based on context:
| Topic | Reference | Load When |
|-------|-----------|-----------|
| Controllers | `references/controllers-routing.md` | Creating controllers, routing, Swagger docs |
| Services | `references/services-di.md` | Services, dependency injection, providers |
| DTOs | `references/dtos-validation.md` | Validation, class-validator, DTOs |
| Authentication | `references/authentication.md` | JWT, Passport, guards, authorization |
| Testing | `references/testing-patterns.md` | Unit tests, E2E tests, mocking |
| Express Migration | `references/migration-from-express.md` | Migrating from Express.js to NestJS |
Read the detailed guide (`references/detailed-guide.md`) before executing this skill. Treat its safety, prerequisites, and validation requirements as mandatory.
## Code Examples
### Controller with DTO Validation and Swagger
```typescript
// create-user.dto.ts
import { IsEmail, IsString, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty({ example: 'user@example.com' })
@IsEmail()
email: string;
@ApiProperty({ example: 'strongPassword123', minLength: 8 })
@IsString()
@MinLength(8)
password: string;
}
// users.controller.ts
import { Body, Controller, Post, HttpCode, HttpStatus } from '@nestjs/common';
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
@ApiTags('users')
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
@ApiCreatedResponse({ description: 'User created successfully.' })
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
}
```
### Service with Dependency Injection and Error Handling
```typescript
// users.service.ts
import { Injectable, ConflictException, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly usersRepository: Repository<User>,
) {}
async create(createUserDto: CreateUserDto): Promise<User> {
const existing = await this.usersRepository.findOneBy({ email: createUserDto.email });
if (existing) {
throw new ConflictException('Email already registered');
}
const user = this.usersRepository.create(createUserDto);
return this.usersRepository.save(user);
}
async findOne(id: number): Promise<User> {
const user = await this.usersRepository.findOneBy({ id });
if (!user) {
throw new NotFoundException(`User #${id} not found`);
}
return user;
}
}
```
### Module Definition
```typescript
// users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { User } from './entities/user.entity';
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
```
### Unit Test for Service
```typescript
// users.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { ConflictException } from '@nestjs/common';
import { UsersService } from './users.service';
import { User } from './entities/user.entity';
const mockRepo = {
findOneBy: jest.fn(),
create: jest.fn(),
save: jest.fn(),
};
describe('UsersService', () => {
let service: UsersService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UsersService,
{ provide: getRepositoryToken(User), useValue: mockRepo },
],
}).compile();
service = module.get<UsersService>(UsersService);
jest.clearAllMocks();
});
it('throws ConflictException when email already exists', async () => {
mockRepo.findOneBy.mockResolvedValue({ id: 1, email: 'user@example.com' });
await expect(
service.create({ email: 'user@example.com', password: 'pass1234' }),
).rejects.toThrow(ConflictException);
});
});
```
## Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.