Skip to main content
Practice Problems

What are dtos and how does validation work in NestJS?

DTOs and Validation in NestJS

DTO (Data Transfer Object) is a class that defines the shape of data flowing into your application. Combined with class-validator and class-transformer, NestJS provides powerful, declarative request validation.


Setup

bash
npm install class-validator class-transformer

Enable the global ValidationPipe in main.ts:

typescript
import { ValidationPipe } from '@nestjs/common'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe({ whitelist: true, // strip unknown properties forbidNonWhitelisted: true, // throw if unknown props sent transform: true, // auto-transform types (string → number) })); await app.listen(3000); }

Creating a DTO

typescript
// dto/create-user.dto.ts import { IsString, IsEmail, IsOptional, IsInt, MinLength, MaxLength, Min, Max, IsEnum } from 'class-validator'; export enum UserRole { USER = 'user', ADMIN = 'admin', } export class CreateUserDto { @IsString() @MinLength(2) @MaxLength(50) name: string; @IsEmail() email: string; @IsOptional() @IsInt() @Min(18) @Max(120) age?: number; @IsOptional() @IsEnum(UserRole) role?: UserRole = UserRole.USER; }

Using DTO in Controller

typescript
@Controller('users') export class UsersController { @Post() create(@Body() createUserDto: CreateUserDto) { // Validation happens automatically! // If invalid → 400 Bad Request with details return this.usersService.create(createUserDto); } }

Validation Error Response

When validation fails, NestJS automatically returns:

json
{ "statusCode": 400, "message": [ "email must be an email", "name must be longer than or equal to 2 characters" ], "error": "Bad Request" }

Update DTO with PartialType

typescript
// dto/update-user.dto.ts import { PartialType } from '@nestjs/mapped-types'; import { CreateUserDto } from './create-user.dto'; // All fields from CreateUserDto become optional export class UpdateUserDto extends PartialType(CreateUserDto) {}

Nested DTOs

typescript
import { Type } from 'class-transformer'; import { ValidateNested, IsArray } from 'class-validator'; export class AddressDto { @IsString() street: string; @IsString() city: string; } export class CreateUserDto { @IsString() name: string; @ValidateNested() @Type(() => AddressDto) address: AddressDto; @IsArray() @ValidateNested({ each: true }) @Type(() => AddressDto) previousAddresses: AddressDto[]; }

Custom Validation Decorator

typescript
import { registerDecorator, ValidationOptions } from 'class-validator'; export function IsSlug(validationOptions?: ValidationOptions) { return (object: object, propertyName: string) => { registerDecorator({ name: 'isSlug', target: object.constructor, propertyName, options: validationOptions, validator: { validate(value: unknown) { return typeof value === 'string' && /^[a-z0-9-]+$/.test(value); }, defaultMessage: () => '$property must be a valid slug', }, }); }; }

Summary

DTOs with class-validator decorators provide declarative, automatic request validation in NestJS. Enable ValidationPipe globally with whitelist: true and transform: true for best security. Use PartialType for update DTOs and ValidateNested for complex nested objects.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems