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
// create-user.dto.ts
export class CreateUserDto {
name: string;
email: string;
password: string;
}Using it in a controller:
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
| Reason | Description |
|---|---|
| A clear data structure | Explicitly states which fields the API accepts |
| Typing | Lets the IDE and the TypeScript compiler check types |
| Security | Prevents "extra" data from the client getting through |
| Validation | A DTO can be annotated with decorators (class-validator) |
| Reuse | The same DTO can be used in several places (e.g. REST and GraphQL) |
DTO ≠ a database model
This is a very important distinction:
| DTO | DB model |
|---|---|
| Defines the data coming in or going out | Defines a table's structure |
| Used at the API/controller level | Used in services/the ORM |
| Can include validation and restricted fields | Contains every column of the table |
Example: CreateUserDto | Example: 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:
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:
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:
{
"name": 123,
"email": "wrong",
"password": "123"
}Nest automatically returns:
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
| Name | Purpose | Example |
|---|---|---|
| Create DTO | For creating an entity | CreateUserDto |
| Update DTO | For (partial) updates | UpdateUserDto |
| Response DTO | For the response format sent to the client | UserResponseDto |
| Query DTO | For 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:
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:
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
| Concept | Description |
|---|---|
| DTO (Data Transfer Object) | A class describing the shape of data passed between layers |
| Main goal | Controlling the input/output data |
| Used in | Controllers (@Body(), @Query(), @Param()) |
| Decorators | @IsString(), @IsEmail(), @MinLength(), @Transform() |
| NestJS tools | ValidationPipe, PartialType, OmitType, PickType |
| Advantages | Security, typing, validation, readability |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.