14.1 NestJS Introduction — Decorator-based TypeScript Framework
What is NestJS?
NestJS is a Node.js server framework written in TypeScript. Inspired by Angular, it is designed around Decorators and Dependency Injection (DI).
Features:
- TypeScript-first: full type safety
- Declarative code with decorators
- Separation of concerns with module system
- Runs on Express/Fastify
- Testability (DI container)
Installation and Project Setup
npm install -g @nestjs/cli
nest new my-project
cd my-project
npm run start:dev
Project Structure
src/
├── app.module.ts # Root module
├── app.controller.ts # Root controller
├── app.service.ts # Root service
├── main.ts # Entry point
└── users/
├── users.module.ts
├── users.controller.ts
├── users.service.ts
└── dto/
├── create-user.dto.ts
└── update-user.dto.ts
Core Components
Module
// users/users.module.ts
import { Module } from '@nestjs/common'
import { UsersController } from './users.controller'
import { UsersService } from './users.service'
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService], // Make available to other modules
})
export class UsersModule {}
// app.module.ts (root module)
import { Module } from '@nestjs/common'
import { UsersModule } from './users/users.module'
import { AuthModule } from './auth/auth.module'
@Module({
imports: [UsersModule, AuthModule],
})
export class AppModule {}
Controller
// users/users.controller.ts
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
HttpCode,
HttpStatus,
} from '@nestjs/common'
import { UsersService } from './users.service'
import { CreateUserDto } from './dto/create-user.dto'
import { UpdateUserDto } from './dto/update-user.dto'
@Controller('users') // /users path
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll(@Query('page') page = '1', @Query('limit') limit = '10') {
return this.usersService.findAll({
page: parseInt(page),
limit: parseInt(limit),
})
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(id)
}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto)
}
@Put(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(id, updateUserDto)
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string) {
return this.usersService.remove(id)
}
}
Service
// users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common'
import { CreateUserDto } from './dto/create-user.dto'
import { UpdateUserDto } from './dto/update-user.dto'
interface User {
id: string
name: string
email: string
createdAt: Date
}
interface PaginationParams {
page: number
limit: number
}
@Injectable()
export class UsersService {
private users: User[] = []
findAll({ page, limit }: PaginationParams) {
const start = (page - 1) * limit
return {
data: this.users.slice(start, start + limit),
total: this.users.length,
page,
limit,
}
}
findOne(id: string): User {
const user = this.users.find(u => u.id === id)
if (!user) {
throw new NotFoundException(`User ID ${id} not found.`)
}
return user
}
create(createUserDto: CreateUserDto): User {
const user: User = {
id: Date.now().toString(),
...createUserDto,
createdAt: new Date(),
}
this.users.push(user)
return user
}
update(id: string, updateUserDto: UpdateUserDto): User {
const user = this.findOne(id)
Object.assign(user, updateUserDto)
return user
}
remove(id: string): void {
const index = this.users.findIndex(u => u.id === id)
if (index === -1) {
throw new NotFoundException(`User ID ${id} not found.`)
}
this.users.splice(index, 1)
}
}
main.ts Configuration
// main.ts
import { NestFactory } from '@nestjs/core'
import { ValidationPipe } from '@nestjs/common'
import { AppModule } from './app.module'
async function bootstrap() {
const app = await NestFactory.create(AppModule)
// Global validation pipe
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // Strip fields not in DTO
forbidNonWhitelisted: true, // Error if extra fields present
transform: true, // Auto type conversion
})
)
// CORS configuration
app.enableCors({
origin: process.env.ALLOWED_ORIGIN ?? '*',
})
// API prefix
app.setGlobalPrefix('api')
await app.listen(process.env.PORT ?? 3000)
console.log(`Server running: http://localhost:${process.env.PORT ?? 3000}`)
}
bootstrap()
Pro Tips
NestJS CLI Commands
# Generate module
nest generate module users
nest g mo users # shorthand
# Generate controller
nest generate controller users
nest g co users
# Generate service
nest generate service users
nest g s users
# Generate full CRUD resource
nest generate resource users
nest g res users # module + controller + service + DTO at once