Reshape and Verify Incoming Values
Pipes — Transform & Validate
Pipes operate on a single method argument. They can transform raw values into typed ones — or validate them and throw 400.
What you'll learn
- Use built-in pipes like ParseIntPipe and ParseUUIDPipe
- Apply pipes at parameter, method, or global scope
- Write a custom pipe that implements PipeTransform
Pipes run between the matched route and the handler. They look at one argument (param, body, query, etc.) and either return a transformed value or throw. They’re the cleanest place to convert “stringly typed” HTTP into real types.
Built-In Pipes
Nest ships several useful ones out of the box. Apply them by passing the pipe class (or instance) as the second argument to the parameter decorator.
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.users.findOne(id); // id is a real number here
}
@Get('by-uuid/:id')
findByUuid(@Param('id', ParseUUIDPipe) id: string) {
return this.users.findOne(id);
}
@Get()
list(@Query('active', ParseBoolPipe) active: boolean) {
return this.users.list({ active });
}
} If parsing fails, the pipe throws BadRequestException — the client sees a
clean 400 with a meaningful message, and your handler never runs.
Default Values
Most parse pipes accept options, including a fallback.
@Get()
list(
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
@Query('size', new DefaultValuePipe(20), ParseIntPipe) size: number,
) {
return this.users.list({ page, size });
} You can chain pipes — they run left to right. DefaultValuePipe supplies a
fallback for missing query strings, then ParseIntPipe does the conversion.
Applying Globally
For project-wide rules (typically validation), register pipes globally in
main.ts.
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
} A Custom Pipe
Implement the PipeTransform interface. transform() gets the raw value
and ArgumentMetadata (which parameter, which type).
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
@Injectable()
export class TrimPipe implements PipeTransform<string, string> {
transform(value: string) {
if (typeof value !== 'string') {
throw new BadRequestException('expected string');
}
return value.trim();
}
} Use it like any built-in pipe:
@Get('search')
search(@Query('q', TrimPipe) q: string) {
return this.posts.search(q);
} The next lesson covers the most important pipe of all — ValidationPipe
with class-validator — which handles whole DTO objects in one go.