Skip to main content

What is a DTO?

What a DTO is

A DTO (Data Transfer Object) is an object used to move data between an application's layers. In NestJS, a DTO is usually a class describing the shape of input or output data (e.g. a request body, query parameters, or a response).

A DTO defines which fields are allowed in and out, and their types.

A simple DTO example

javascript
// create-user.dto.ts export class CreateUserDto { name: string; email: string; password: string; }

Using it in a controller:

javascript
import { Body, Controller, Post } from '@nestjs/common'; import { CreateUserDto } from './create-user.dto'; @Controller('users') export class UsersController { @Post() create(@Body() dto: CreateUserDto) { // dto: { name, email, password } return `Created user: ${dto.name}`; } }

Now Nest expects exactly these fields to arrive in the request body.

Why DTOs are needed

ReasonDescription
A clear data structureExplicitly states which fields the API accepts
TypingLets the IDE and the TypeScript compiler check types
SecurityPrevents "extra" data from the client getting through
ValidationA DTO can be annotated with decorators (class-validator)
ReuseThe same DTO can be used in several places (e.g. REST and GraphQL)

DTO ≠ a database model

This is a very important distinction:

DTODB model
Defines the data coming in or going outDefines a table's structure
Used at the API/controller levelUsed in services/the ORM
Can include validation and restricted fieldsContains every column of the table
Example: CreateUserDtoExample: UserEntity (in Prisma or TypeORM)

Validating a DTO

DTOs are usually used together with:

  • class-validator, for checking the data;
  • class-transformer, for converting plain objects into class instances.

Example:

javascript
import { IsEmail, IsString, MinLength } from 'class-validator'; export class CreateUserDto { @IsString() name: string; @IsEmail() email: string; @MinLength(6) password: string; }

And enabling validation in main.ts:

javascript
import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe()); await app.listen(3000); } bootstrap();

Now if a client sends:

javascript
{ "name": 123, "email": "wrong", "password": "123" }

Nest automatically returns:

javascript
400 Bad Request [ { "property": "name", "constraints": { "isString": "name must be a string" } }, { "property": "email", "constraints": { "isEmail": "email must be an email" } }, { "property": "password", "constraints": { "minLength": "password must be longer than or equal to 6 characters" } } ]

Different kinds of DTO

NamePurposeExample
Create DTOFor creating an entityCreateUserDto
Update DTOFor (partial) updatesUpdateUserDto
Response DTOFor the response format sent to the clientUserResponseDto
Query DTOFor request parameters (?limit=10&page=2)GetUsersQueryDto

An Update DTO example (partial fields)

NestJS provides a PartialType() utility from @nestjs/mapped-types to derive one DTO with optional fields from another:

javascript
import { PartialType } from '@nestjs/mapped-types'; import { CreateUserDto } from './create-user.dto'; export class UpdateUserDto extends PartialType(CreateUserDto) {}

Now every field of CreateUserDto becomes optional, perfect for PATCH requests.

DTOs and data transformation

class-transformer can be applied to automatically convert data:

javascript
import { Transform } from 'class-transformer'; import { IsNumber } from 'class-validator'; export class QueryDto { @Transform(({ value }) => parseInt(value)) @IsNumber() limit: number; }

Now if ?limit=10 comes in, Nest automatically converts limit to a number.

Tips for DTOs

Split DTOs by purpose (Create, Update, Response); Use class-validator + ValidationPipe; DTO ≠ Entity, don't mix the layers; Import a DTO only into controllers and services; A DTO should be simple and predictable, with no business logic.

Summary

ConceptDescription
DTO (Data Transfer Object)A class describing the shape of data passed between layers
Main goalControlling the input/output data
Used inControllers (@Body(), @Query(), @Param())
Decorators@IsString(), @IsEmail(), @MinLength(), @Transform()
NestJS toolsValidationPipe, PartialType, OmitType, PickType
AdvantagesSecurity, typing, validation, readability

Short Answer

Interview ready
Premium

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