What are pipes in NestJS?
Pipes in NestJS
Pipes transform and validate input data before it reaches the route handler. They implement the PipeTransform interface and operate on the arguments passed to a controller method.
Pipes have two main use cases:
- Validation — validate and throw if invalid
- Transformation — convert data to a different type
Built-in Pipes
| Pipe | Purpose |
|---|---|
ValidationPipe | Validate with class-validator / DTOs |
ParseIntPipe | Convert string to integer |
ParseFloatPipe | Convert string to float |
ParseBoolPipe | Convert string to boolean |
ParseArrayPipe | Parse array values |
ParseUUIDPipe | Validate UUID format |
ParseEnumPipe | Validate against enum values |
DefaultValuePipe | Provide a default value |
Using Built-in Pipes
typescript
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
// id is already a number, never a string!
return this.usersService.findOne(id);
}
// With custom error status
@Get(':id')
findOne(
@Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }))
id: number
) { ... }
// ParseUUIDPipe
@Get(':uuid')
findOne(@Param('uuid', ParseUUIDPipe) uuid: string) { ... }
// DefaultValuePipe
@Get()
findAll(
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
@Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number,
) { ... }Custom Pipe
typescript
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
@Injectable()
export class PositiveIntPipe implements PipeTransform<string, number> {
transform(value: string, metadata: ArgumentMetadata): number {
const num = parseInt(value, 10);
if (isNaN(num)) {
throw new BadRequestException(`${metadata.data} must be a number`);
}
if (num <= 0) {
throw new BadRequestException(`${metadata.data} must be positive`);
}
return num;
}
}
// Usage:
@Get(':id')
findOne(@Param('id', PositiveIntPipe) id: number) { ... }Validation Pipe (Most Important)
typescript
// Global — applies to all routes
app.useGlobalPipes(new ValidationPipe({
whitelist: true, // strip unknown properties
forbidNonWhitelisted: true, // error on unknown properties
transform: true, // auto-cast types
transformOptions: {
enableImplicitConversion: true, // string '1' → number 1
},
errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY, // 422 instead of 400
}));
// Route-level override
@Post()
@UsePipes(new ValidationPipe({ whitelist: true }))
create(@Body() dto: CreateUserDto) { ... }Pipe Binding Levels
typescript
// Parameter-level (most specific)
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {}
// Method-level
@Post()
@UsePipes(ValidationPipe)
create(@Body() dto: CreateUserDto) {}
// Controller-level
@Controller('users')
@UsePipes(new ValidationPipe())
export class UsersController {}
// Global (in main.ts or via APP_PIPE)
app.useGlobalPipes(new ValidationPipe());
// or:
{ provide: APP_PIPE, useClass: ValidationPipe }Parsing Query Arrays
typescript
@Get()
findAll(
@Query('ids', new ParseArrayPipe({ items: Number, separator: ',' }))
ids: number[]
) {
// GET /users?ids=1,2,3 → ids = [1, 2, 3]
return this.usersService.findByIds(ids);
}Summary
Pipes are the data processing layer of NestJS. Always use ValidationPipe globally with whitelist: true and transform: true. Use ParseIntPipe, ParseUUIDPipe, etc. for URL/query parameter type coercion. Create custom pipes for domain-specific validation logic.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.