Pipes operate on the arguments passed to a route handler, transforming or validating them before the handler runs. This lesson covers the PipeTransform interface and NestJS's built-in pipes.
What Is a Pipe?
A pipe is a class implementing PipeTransform, with a single transform() method that receives the incoming value and metadata about it, and returns the (possibly converted) value, or throws an exception to reject it.
import { PipeTransform, ArgumentMetadata, BadRequestException } from '@nestjs/common';
export class ParsePositiveIntPipe implements PipeTransform {
transform(value: string, metadata: ArgumentMetadata): number {
const parsed = Number(value);
if (!Number.isInteger(parsed) || parsed <= 0) {
throw new BadRequestException(`${metadata.data} must be a positive integer`);
}
return parsed;
}
}
ArgumentMetadata tells the pipe what kind of argument it's processing (body, query, param, or custom) and the parameter's name, useful for building descriptive error messages.
Throwing inside a pipe automatically produces the corresponding HTTP error response.
Pipes run after guards and interceptors' pre-handler logic, but before the route handler itself.
Built-in Pipes Cheatsheet
Pipes shipped with @nestjs/common for common conversions.
Pipe
Purpose
ValidationPipe
Validates a value against a DTO's class-validator rules
ParseIntPipe
Converts and validates a value as an integer
ParseFloatPipe
Converts and validates a value as a float
ParseBoolPipe
Converts "true"/"false" strings to booleans
ParseUUIDPipe
Validates a value as a UUID
ParseArrayPipe
Parses and validates an array of values
DefaultValuePipe
Supplies a default when a value is undefined
Transformation Pipes vs. Validation Pipes
Pipes serve two overlapping purposes: transformation (converting a string to a number, applying a default) and validation (rejecting values that don't meet certain rules). Many built-in pipes, like ParseIntPipe, do both at once.
Combining Multiple Pipes
A single parameter can pass through multiple pipes in sequence, each receiving the previous pipe's output, useful for combining a default value with type conversion.
Confusing pipes (data transformation/validation) with guards (authorization decisions).
Applying ValidationPipe only at the route level when most projects benefit from it globally.
Forgetting DefaultValuePipe needs to run before ParseIntPipe in the pipe list to supply a fallback first.
Writing a custom pipe that mutates its input in place instead of returning a new transformed value.
Key Takeaways
Pipes implement PipeTransform and either transform or validate handler arguments.
Pipes can be scoped to a parameter, route, controller, or the whole application.
Built-in pipes cover the most common numeric, boolean, UUID, and array conversions.
Multiple pipes can be chained, each receiving the previous pipe's output.
Pro Tip
Reach for a built-in pipe (ParseIntPipe, ParseUUIDPipe, DefaultValuePipe) before writing a custom one, the vast majority of parameter conversion needs are already covered, and custom pipes are best reserved for domain-specific rules.
You now understand pipes in general. Next, look specifically at the Validation Pipe, the most commonly used pipe in any NestJS app.