Skip to content

NestJS ValidationPipe

ValidationPipe is the single most commonly used pipe in any real NestJS application. This lesson goes deeper into how it works internally and how to configure it precisely.

How ValidationPipe Works Internally

When applied to a parameter typed as a DTO class, ValidationPipe uses class-transformer to convert the plain incoming object into an actual instance of that class, then uses class-validator to run every validation decorator declared on it, throwing a BadRequestException if any fail.

app.useGlobalPipes(
  new ValidationPipe({
    whitelist: true,
    forbidNonWhitelisted: true,
    transform: true,
  }),
);

This configuration strips unknown fields, rejects requests containing them outright, and converts plain payloads into real DTO instances, a solid default for most production APIs.

Key Configuration Options

new ValidationPipe({
  whitelist: true,
  forbidNonWhitelisted: true,
  transform: true,
  disableErrorMessages: false,
  stopAtFirstError: false,
})
  • whitelist strips properties not declared on the DTO.
  • forbidNonWhitelisted rejects the request instead of silently stripping unknown properties.
  • disableErrorMessages hides detailed validation messages, useful in production for security.
  • stopAtFirstError returns only the first validation failure per field instead of all of them.

ValidationPipe Options Cheatsheet

The options you'll configure most often.

Option Effect
whitelist Strips unknown properties from the payload
forbidNonWhitelisted Throws instead of stripping unknown properties
transform Converts plain objects into DTO class instances
skipMissingProperties Skips validation for properties that are undefined
exceptionFactory Customizes the shape of the thrown validation error

Using Validation Groups

class-validator supports validation groups, letting a single DTO apply different rules depending on context (like requiring a field only on create, not on update), passed through ValidationPipe's options.

class CatDto {
  @IsString({ groups: ['create'] })
  name: string;
}

new ValidationPipe({ groups: ['create'] });

Async Validators

Custom validators that need to check a database (like ensuring an email isn't already taken) can be async. ValidationPipe awaits these automatically, but keep in mind they add real latency to every validated request.

Common Mistakes

  • Leaving disableErrorMessages off in production, potentially leaking implementation details in error responses.
  • Not setting forbidNonWhitelisted, silently dropping fields a client believed were being saved.
  • Writing expensive async validators without considering their performance impact on every request.
  • Assuming ValidationPipe validates nested objects automatically without @ValidateNested() and @Type().

Key Takeaways

  • ValidationPipe combines class-transformer and class-validator to validate DTOs automatically.
  • whitelist, forbidNonWhitelisted, and transform are the most commonly tuned options.
  • Validation groups let one DTO support different rules for different operations.
  • Async custom validators are supported but should be used carefully for performance reasons.

Pro Tip

Set disableErrorMessages: true (or a custom exceptionFactory that redacts details) in production environments specifically, while keeping full error messages in development, this avoids leaking internal validation logic to API consumers while still helping your own team debug locally.