Back to skills
SKILL.md
Nestjs Project Architect
ASecurityProduction-ready NestJS project structure with modules, guards, interceptors, and enterprise patterns. Use when scaffolding, structuring, or architecting nestjs projects.
- 9 stars
- 0 votes
- 0 copies
- 1 view
- Added September 8, 2026
Works with
Security analysis
100/100npx -y skills add anubhavg-icpl/vibe --skill nestjs-project-architect --agent claude-codeAre you the author of Nestjs Project Architect?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-nestjs-project-architect)---
name: nestjs-project-architect
description: Production-ready NestJS project structure with modules, guards, interceptors, and enterprise patterns. Use when scaffolding, structuring, or architecting nestjs projects.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: project-structure
tags: [nestjs, nodejs, typescript, api, project-structure, enterprise]
---
# NestJS Project Architect Mode
You are an expert in structuring production-ready NestJS applications with modular architecture, proper dependency injection, and enterprise patterns.
## Project Structure
```text
nestjs-project/
├── src/
│ ├── main.ts # Application entry point
│ ├── app.module.ts # Root module
│ │
│ ├── common/
│ │ ├── decorators/
│ │ │ ├── current-user.decorator.ts
│ │ │ └── roles.decorator.ts
│ │ ├── filters/
│ │ │ ├── http-exception.filter.ts
│ │ │ └── all-exceptions.filter.ts
│ │ ├── guards/
│ │ │ ├── jwt-auth.guard.ts
│ │ │ └── roles.guard.ts
│ │ ├── interceptors/
│ │ │ ├── logging.interceptor.ts
│ │ │ ├── transform.interceptor.ts
│ │ │ └── timeout.interceptor.ts
│ │ ├── pipes/
│ │ │ └── validation.pipe.ts
│ │ ├── middleware/
│ │ │ └── logger.middleware.ts
│ │ └── interfaces/
│ │ └── index.ts
│ │
│ ├── config/
│ │ ├── configuration.ts
│ │ ├── database.config.ts
│ │ └── validation.schema.ts
│ │
│ ├── database/
│ │ ├── database.module.ts
│ │ ├── migrations/
│ │ └── seeds/
│ │
│ ├── modules/
│ │ ├── auth/
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── strategies/
│ │ │ │ ├── jwt.strategy.ts
│ │ │ │ └── local.strategy.ts
│ │ │ └── dto/
│ │ │ ├── login.dto.ts
│ │ │ └── register.dto.ts
│ │ │
│ │ ├── users/
│ │ │ ├── users.module.ts
│ │ │ ├── users.controller.ts
│ │ │ ├── users.service.ts
│ │ │ ├── users.repository.ts
│ │ │ ├── entities/
│ │ │ │ └── user.entity.ts
│ │ │ └── dto/
│ │ │ ├── create-user.dto.ts
│ │ │ └── update-user.dto.ts
│ │ │
│ │ └── items/
│ │ ├── items.module.ts
│ │ ├── items.controller.ts
│ │ ├── items.service.ts
│ │ ├── entities/
│ │ │ └── item.entity.ts
│ │ └── dto/
│ │ ├── create-item.dto.ts
│ │ └── update-item.dto.ts
│ │
│ └── shared/
│ ├── shared.module.ts
│ └── services/
│ ├── cache.service.ts
│ └── email.service.ts
│
├── test/
│ ├── app.e2e-spec.ts
│ ├── jest-e2e.json
│ └── utils/
│ └── test-helper.ts
│
├── docker/
│ ├── Dockerfile
│ └── docker-compose.yml
│
├── .env.example
├── .eslintrc.js
├── .prettierrc
├── nest-cli.json
├── package.json
├── tsconfig.json
├── tsconfig.build.json
└── README.md
```
## Core Files
```typescript
// src/main.ts
import { NestFactory } from "@nestjs/core";
import { ValidationPipe, VersioningType } from "@nestjs/common";
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import { ConfigService } from "@nestjs/config";
import helmet from "helmet";
import { AppModule } from "./app.module";
import { HttpExceptionFilter } from "./common/filters/http-exception.filter";
import { LoggingInterceptor } from "./common/interceptors/logging.interceptor";
import { TransformInterceptor } from "./common/interceptors/transform.interceptor";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
// Security
app.use(helmet());
app.enableCors({
origin: configService.get("CORS_ORIGINS")?.split(",") || [],
credentials: true,
});
// Versioning
app.enableVersioning({
type: VersioningType.URI,
defaultVersion: "1",
});
// Global pipes, filters, interceptors
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
transformOptions: { enableImplicitConversion: true },
}),
);
app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalInterceptors(new LoggingInterceptor(), new TransformInterceptor());
// Swagger
const config = new DocumentBuilder()
.setTitle("API")
.setDescription("API Documentation")
.setVersion("1.0")
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup("docs", app, document);
const port = configService.get("PORT") || 3000;
await app.listen(port);
}
bootstrap();
```
```typescript
// src/app.module.ts
import { Module, MiddlewareConsumer } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { TypeOrmModule } from "@nestjs/typeorm";
import configuration from "./config/configuration";
import { DatabaseConfig } from "./config/database.config";
import { LoggerMiddleware } from "./common/middleware/logger.middleware";
import { AuthModule } from "./modules/auth/auth.module";
import { UsersModule } from "./modules/users/users.module";
import { ItemsModule } from "./modules/items/items.module";
import { SharedModule } from "./shared/shared.module";
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [configuration],
}),
TypeOrmModule.forRootAsync({
useClass: DatabaseConfig,
}),
AuthModule,
UsersModule,
ItemsModule,
SharedModule,
],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggerMiddleware).forRoutes("*");
}
}
```
```typescript
// src/modules/users/users.module.ts
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { UsersController } from "./users.controller";
import { UsersService } from "./users.service";
import { UsersRepository } from "./users.repository";
import { User } from "./entities/user.entity";
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService, UsersRepository],
exports: [UsersService],
})
export class UsersModule {}
```
```typescript
// src/modules/users/users.controller.ts
import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, ParseIntPipe } from "@nestjs/common";
import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from "@nestjs/swagger";
import { JwtAuthGuard } from "../../common/guards/jwt-auth.guard";
import { RolesGuard } from "../../common/guards/roles.guard";
import { Roles } from "../../common/decorators/roles.decorator";
import { CurrentUser } from "../../common/decorators/current-user.decorator";
import { UsersService } from "./users.service";
import { CreateUserDto } from "./dto/create-user.dto";
import { UpdateUserDto } from "./dto/update-user.dto";
import { User } from "./entities/user.entity";
@ApiTags("Users")
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
@ApiOperation({ summary: "Get all users" })
@Roles("admin")
async findAll(@Query("page") page = 1, @Query("limit") limit = 10) {
return this.usersService.findAll({ page, limit });
}
@Get("me")
@ApiOperation({ summary: "Get current user" })
async getMe(@CurrentUser() user: User) {
return user;
}
@Get(":id")
@ApiOperation({ summary: "Get user by ID" })
async findOne(@Param("id", ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
@Post()
@ApiOperation({ summary: "Create user" })
@Roles("admin")
async create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Put(":id")
@ApiOperation({ summary: "Update user" })
async update(@Param("id", ParseIntPipe) id: number, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(id, updateUserDto);
}
@Delete(":id")
@ApiOperation({ summary: "Delete user" })
@Roles("admin")
async remove(@Param("id", ParseIntPipe) id: number) {
return this.usersService.remove(id);
}
}
```
```typescript
// src/modules/users/users.service.ts
import { Injectable, NotFoundException } from "@nestjs/common";
import { UsersRepository } from "./users.repository";
import { CreateUserDto } from "./dto/create-user.dto";
import { UpdateUserDto } from "./dto/update-user.dto";
@Injectable()
export class UsersService {
constructor(private readonly usersRepository: UsersRepository) {}
async findAll(options: { page: number; limit: number }) {
return this.usersRepository.findWithPagination(options);
}
async findOne(id: number) {
const user = await this.usersRepository.findById(id);
if (!user) {
throw new NotFoundException(`User #${id} not found`);
}
return user;
}
async findByEmail(email: string) {
return this.usersRepository.findByEmail(email);
}
async create(createUserDto: CreateUserDto) {
return this.usersRepository.create(createUserDto);
}
async update(id: number, updateUserDto: UpdateUserDto) {
await this.findOne(id);
return this.usersRepository.update(id, updateUserDto);
}
async remove(id: number) {
await this.findOne(id);
return this.usersRepository.delete(id);
}
}
```
```typescript
// src/common/guards/jwt-auth.guard.ts
import { Injectable, ExecutionContext } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { Reflector } from "@nestjs/core";
@Injectable()
export class JwtAuthGuard extends AuthGuard("jwt") {
constructor(private reflector: Reflector) {
super();
}
canActivate(context: ExecutionContext) {
const isPublic = this.reflector.getAllAndOverride<boolean>("isPublic", [context.getHandler(), context.getClass()]);
if (isPublic) {
return true;
}
return super.canActivate(context);
}
}
```
```typescript
// src/common/interceptors/transform.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from "@nestjs/common";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
export interface Response<T> {
data: T;
meta?: Record<string, any>;
}
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
return next.handle().pipe(
map((data) => ({
data,
timestamp: new Date().toISOString(),
})),
);
}
}
```
## Best Practices
- One module per feature/domain
- Use DTOs with class-validator for input validation
- Implement repository pattern for data access
- Use guards for authentication/authorization
- Use interceptors for cross-cutting concerns
- Use custom decorators for clean controller code
- Version your API from day one
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.