Pipes — Transform & Validate

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.

4 min read Level 2/5 #nestjs#pipes#validation
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.

The Built-In ValidationPipe →