Validating DTOs with class-validator
Decorate DTO properties with class-validator rules like @IsString and @IsEmail.
Syntax
@IsEmail() email: string;class-validator provides decorators you attach to DTO properties. Combined with the ValidationPipe, they enforce rules on incoming data.
Common decorators
| Decorator | Checks |
|---|---|
@IsString() | Value is a string |
@IsEmail() | Valid email format |
@IsInt() | Whole number |
@Min(n) / @Max(n) | Numeric range |
@IsOptional() | Property may be omitted |
If any rule fails, the ValidationPipe throws a 400 with a list of messages before your handler runs.
Example
import { IsString, IsEmail, IsInt, Min } from 'class-validator';
export class CreateUserDto {
@IsString()
name: string;
@IsEmail()
email: string;
@IsInt()
@Min(0)
age: number;
}When to use it
- A developer decorates an email field with @IsEmail() so the ValidationPipe rejects invalid email formats before the service even receives the data.
- A team uses @IsOptional() combined with @MinLength(8) on a password field so the field is not required but must meet length rules if provided.
- An engineer uses @ValidateNested() with @Type(() => AddressDto) to validate a nested object inside a parent DTO.
More examples
DTO with common validators
Shows a DTO with string, email, integer range, and optional string validators in a single class.
import { IsString, IsEmail, IsInt, Min, Max, IsOptional } from 'class-validator';
export class CreateUserDto {
@IsString()
name: string;
@IsEmail()
email: string;
@IsInt()
@Min(18)
@Max(120)
age: number;
@IsOptional()
@IsString()
bio?: string;
}Nested object validation
Uses @ValidateNested with @Type to recursively validate a nested DTO object inside a parent DTO.
import { ValidateNested, IsString } from 'class-validator';
import { Type } from 'class-transformer';
export class AddressDto {
@IsString() street: string;
@IsString() city: string;
}
export class CreateOrderDto {
@ValidateNested()
@Type(() => AddressDto)
shippingAddress: AddressDto;
}Custom error messages
Passes a message option to each decorator so validation errors return human-readable messages instead of defaults.
import { IsString, MinLength, IsEmail } from 'class-validator';
export class RegisterDto {
@IsString({ message: 'Username must be text' })
@MinLength(3, { message: 'Username too short β min 3 chars' })
username: string;
@IsEmail({}, { message: 'Please provide a valid email address' })
email: string;
}
Discussion