Skip to content

class-validator

Developer UtilitiesValidationTypeScript

What it is

class-validator validates objects using decorators on class properties, and is the validation layer built into NestJS.

Decorate class properties with constraints and call validate(). Because decorators need a runtime class, this cannot work with interfaces or type aliases.

Installation

npm install class-validator class-transformer

Getting started

The smallest useful thing you can do with it, and what each part means.

Decorated DTO
import { IsEmail, IsInt, Min, Max, IsOptional, Length } from 'class-validator';

export class CreateUserDto {
  @IsEmail()
  email: string;

  @IsInt() @Min(13) @Max(130)
  age: number;

  @IsOptional() @Length(0, 500)
  bio?: string;
}

const errors = await validate(dto);
if (errors.length) {
  const messages = errors.flatMap((e) => Object.values(e.constraints ?? {}));
  throw new BadRequestException(messages);
}
validate returns an array rather than throwing. An empty array means valid — checking truthiness of the array itself is always true and is a classic mistake.

Advanced usage

Where the library earns its place over a simpler alternative.

Nested objects and plain-object conversion
import { plainToInstance } from 'class-transformer';

class Address {
  @Length(1, 100) street: string;
}

class User {
  @ValidateNested() @Type(() => Address)
  address: Address;

  @ValidateNested({ each: true }) @Type(() => Address)
  previous: Address[];
}

// JSON.parse gives a plain object; decorators need a real instance.
const user = plainToInstance(User, JSON.parse(body));
const errors = await validate(user, { whitelist: true });
This is the step people miss. Passing a plain object straight to validate silently validates nothing, because the metadata lives on the class.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

Validation always passes
The object is a plain object, not a class instance. Convert it with plainToInstance.
Reflect.getMetadata is not a function
import 'reflect-metadata' once at the application entry point, before anything else.

Best practices

  • Always convert with plainToInstance first; validating a plain object silently passes.
  • Add @ValidateNested and @Type for nested structures — they are not traversed by default.
  • Use whitelist: true to strip unknown properties.
  • Prefer Zod for new non-Nest projects; it needs no decorators or reflect-metadata.

Background

Why it exists, and what it was reacting to.

It brought the annotation-driven validation style familiar from Java's Bean Validation to TypeScript, which is why it pairs naturally with the decorator-heavy NestJS architecture.