Skip to main content
Practice Problems

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:

  1. Validation — validate and throw if invalid
  2. Transformation — convert data to a different type

Built-in Pipes

PipePurpose
ValidationPipeValidate with class-validator / DTOs
ParseIntPipeConvert string to integer
ParseFloatPipeConvert string to float
ParseBoolPipeConvert string to boolean
ParseArrayPipeParse array values
ParseUUIDPipeValidate UUID format
ParseEnumPipeValidate against enum values
DefaultValuePipeProvide 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 ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems