NestJS Validation Tutorial Using class-validator and class-transformer
Defining a DTO gives you compile-time type safety, but TypeScript types disappear entirely once your code compiles to JavaScript, meaning they offer zero protection against bad data at runtime. If a client sends a completely malformed request, missing required fields or sending the wrong data types, your DTO alone will not stop it.
This is exactly the gap that class-validator and class-transformer fill. Together with NestJS's built-in ValidationPipe, they transform your DTOs from compile-time-only contracts into runtime-enforced rules, automatically rejecting bad requests before they ever reach your controller logic.
NestJS Validation Class-validator: Learning Objectives
- Understand why TypeScript types alone cannot validate data at runtime.
- Add validation rules to a DTO using class-validator decorators.
- Enable automatic validation across an application using ValidationPipe.
- Understand the role of class-transformer in converting plain objects into DTO instances.
- Configure validation options like whitelist and forbidNonWhitelisted for stricter APIs.
NestJS Validation Class-validator: Key Terms and Definitions
- class-validator: A library providing decorators like @IsString(), @IsEmail(), and @IsNotEmpty() that attach runtime validation rules to class properties.
- class-transformer: A library that converts plain JavaScript objects into instances of a specific class, preserving type information needed for validation and transformation.
- ValidationPipe: A built-in NestJS pipe that automatically validates incoming request data against a DTO's class-validator rules before it reaches a route handler.
- Whitelist option: A ValidationPipe setting that strips any properties from incoming data that are not explicitly declared in the DTO.
- forbidNonWhitelisted option: A ValidationPipe setting that rejects a request entirely (rather than silently stripping) if it contains properties not declared in the DTO.
How NestJS Validation Class-validator Works: Detailed Explanation
TypeScript's type system is a compile-time tool. Once your NestJS application is compiled to JavaScript and running, there is no remaining trace of types like CreateUserDto enforcing that email must genuinely be a string, let alone a validly formatted email address. A malicious or simply buggy client could send { "email": 12345 } and, without runtime validation, this incorrect data would flow straight into your business logic.
class-validator solves this by providing decorators you attach directly to DTO properties, describing runtime validation rules. For example, @IsEmail() on the email property ensures the value is a syntactically valid email address, @IsString() ensures a value is genuinely a string, @IsNotEmpty() ensures a required field was not left blank, and @MinLength(8) can enforce a minimum password length. These decorators do not run automatically on their own; they simply attach metadata to the DTO class, similar to how NestJS's own decorators work.
This is where class-transformer and NestJS's ValidationPipe come in. When a request arrives, the incoming JSON body is initially just a plain JavaScript object, not an actual instance of your DTO class, meaning class-validator's decorator metadata is not automatically checked against it. class-transformer's plainToInstance function (used internally by ValidationPipe) converts this plain object into a real instance of the DTO class, at which point class-validator's validate function can inspect it against every decorator rule that was attached.
NestJS ties all of this together automatically through its built-in ValidationPipe. Applying it globally, in main.ts using app.useGlobalPipes(new ValidationPipe()), ensures every incoming request body across your entire application is automatically transformed and validated against its corresponding DTO before the route handler even executes. If validation fails, NestJS automatically returns a 400 Bad Request response describing exactly which fields failed and why, without you writing a single line of manual validation logic in your controllers.
Two particularly valuable ValidationPipe options are whitelist and forbidNonWhitelisted. Setting whitelist: true automatically strips out any properties sent by the client that are not explicitly declared in the DTO, protecting against unexpected or malicious extra fields. Setting forbidNonWhitelisted: true goes a step further, rejecting the entire request with an error if any undeclared properties are present, rather than silently stripping them, which is useful for stricter APIs that want to surface client-side mistakes immediately.
Interview-Friendly Explanation
A strong interview or viva answer for nestjs validation class-validator must go beyond a one-line definition. Interviewers evaluating BCA, MCA, B.Tech, and self-taught backend developers reward answers that combine a precise definition, a clear working explanation, a real-world example, and a conclusion that highlights why it matters in production Node.js applications. Use the four-point framework below when answering under time pressure.
- Definition point: class-validator: A library providing decorators like @IsString(), @IsEmail(), and @IsNotEmpty() that attach runtime validation rules to class properties.
- Working point: Add validation rules to a DTO using class-validator decorators.
- Example point: Signup and registration endpoints across virtually every production NestJS application rely on class-validator rules like @IsEmail() and @MinLength() to reject malformed accounts before they ever reach the database.
- Conclusion point: TypeScript types protect you at compile time; class-validator and ValidationPipe protect you at runtime — you need both.
How to Answer This in a Technical Interview
- Give a two-to-three sentence definition using correct NestJS and Node.js terminology.
- Add one specific example drawn from a real backend scenario such as an e-commerce, fintech, or SaaS API.
- Mention the request lifecycle stage this concept operates at (pipe, guard, middleware, filter, interceptor) since interviewers often test whether you know the execution order.
- Close with one benefit, trade-off, or production use case.
- Avoid vague answers like "it just validates stuff" — interviewers filter these out immediately.
Practical Scenario
Imagine you are hardening a production API for a SaaS product, similar to systems used at companies like Razorpay, Freshworks, or Postman. Every lesson in this module maps directly to a decision you will make while making that backend secure, predictable, and resilient to bad input: validating what comes in, transforming it safely, catching failures gracefully, and protecting routes from unauthorized access.
NestJS Validation Class-validator: Architecture and Flow Diagram
Visualize a request validation pipeline:
[Raw JSON body from client] --> [class-transformer: plainToInstance() converts to DTO instance] --> [class-validator: checks decorator rules like @IsEmail, @IsNotEmpty] --> [Valid? Yes --> Controller executes | No --> 400 Bad Request returned automatically]
Add a note: 'This entire pipeline runs automatically once ValidationPipe is registered globally.'
NestJS Validation Class-validator: Decorator Reference Table
| Decorator | Purpose | Example |
|---|---|---|
| @IsString() | Ensures the value is a string | @IsString() name: string; |
| @IsEmail() | Ensures the value is a valid email format | @IsEmail() email: string; |
| @IsNotEmpty() | Ensures the value is not empty or undefined | @IsNotEmpty() name: string; |
| @MinLength(n) | Ensures a string has at least n characters | @MinLength(8) password: string; |
| @IsOptional() | Marks a property as optional during validation | @IsOptional() age?: number; |
| @IsInt() | Ensures the value is an integer | @IsInt() age: number; |
NestJS Validation Class-validator: NestJS Code Example
// dto/create-user.dto.ts — DTO with validation rules attached
import { IsEmail, IsNotEmpty, IsOptional, IsString, MinLength, IsInt, Min } from 'class-validator';
export class CreateUserDto {
@IsString()
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
@IsOptional()
@IsInt()
@Min(13)
age?: number;
}
// main.ts — enabling global validation for the whole application
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // strips properties not defined in the DTO
forbidNonWhitelisted: true, // rejects requests with unknown properties
transform: true, // automatically converts payloads to DTO instances
}),
);
await app.listen(3000);
}
bootstrap();
CreateUserDto now carries real runtime validation rules: name must be a non-empty string, email must be a validly formatted email address, password must be a string of at least 8 characters, and age, if provided, must be an integer of at least 13. Once ValidationPipe is registered globally in main.ts with whitelist, forbidNonWhitelisted, and transform all enabled, every request body across the entire application is automatically checked against its corresponding DTO's rules. A request missing a required email, or sending an unexpected extra field, is rejected automatically with a clear 400 Bad Request response, with zero manual validation code written inside any controller.
Real-World NestJS Validation Class-validator Industry Examples
- Signup and registration endpoints across virtually every production NestJS application rely on class-validator rules like @IsEmail() and @MinLength() to reject malformed accounts before they ever reach the database.
- Fintech and payment APIs use strict validation, often combined with forbidNonWhitelisted, to ensure no unexpected or potentially malicious extra fields slip into sensitive requests like fund transfers.
- Public APIs exposed to third-party developers rely heavily on automatic ValidationPipe error messages to give external developers immediate, clear feedback about malformed requests without needing custom error-handling code.
- E-commerce checkout flows validate deeply nested DTOs (an order containing an array of line items) using class-validator's nested validation support to ensure every item in the array also passes its own rules.
NestJS Validation Class-validator Interview Questions and Answers
Q1. Why isn't TypeScript's type system enough to validate incoming request data?
Short answer: TypeScript types are a compile-time-only construct and are completely erased once code is compiled to JavaScript. At runtime, there is no mechanism enforcing that a field claimed to be a string actually is one, which is why a separate runtime validation library like class-validator is necessary to enforce these rules when the application is actually running.
Detailed explanation: TypeScript's type system is a compile-time tool. Once your NestJS application is compiled to JavaScript and running, there is no remaining trace of types like CreateUserDto enforcing that email must genuinely be a string, let alone a validly formatted email address. A malicious or simply buggy client could send { "email": 12345 } and, without runtime validation, this incorrect data would flow straight into your business logic. class-validator solves this by providing decorators you attach directly to DTO properties, describing runtime validation rules. For example, @IsEmail() on the email property ensures the value is a syntactically valid email address, @IsString() ensures a value is genuinely a string, @IsNotEmpty() ensures a required field was not left blank, and @MinLength(8) can enforce a minimum password length. These decorators do not run automatically on their own; they simply attach metadata to the DTO class, similar to how NestJS's own decorators work. This is where class-transformer and NestJS's ValidationPipe come in. When a request arrives, the incoming JSON body is initially just a plain JavaScript object, not an actual instance of your DTO class, meaning class-validator's decorator metadata is not automatically checked against it. class-transformer's plainToInstance function (used internally by ValidationPipe) converts this plain object into a real instance of the DTO class, at which point class-validator's validate function can inspect it against every decorator rule that was attached. NestJS ties all of this together automatically through its built-in ValidationPipe. Applying it globally, in main.ts using app.useGlobalPipes(new ValidationPipe()), ensures every incoming request body across your entire application is automatically transformed and validated against its corresponding DTO before the route handler even executes. If validation fails, NestJS automatically returns a 400 Bad Request response describing exactly which fields failed and why, without you writing a single line of manual validation logic in your controllers. Two particularly valuable ValidationPipe options are whitelist and forbidNonWhitelisted. Setting whitelist: true automatically strips out any properties sent by the client that are not explicitly declared in the DTO, protecting against unexpected or malicious extra fields. Setting forbidNonWhitelisted: true goes a step further, rejecting the entire request with an error if any undeclared properties are present, rather than silently stripping them, which is useful for stricter APIs that want to surface client-side mistakes immediately.
Practical example: Signup and registration endpoints across virtually every production NestJS application rely on class-validator rules like @IsEmail() and @MinLength() to reject malformed accounts before they ever reach the database.
Interview tip: class-validator provides decorators (like @IsEmail, @IsNotEmpty) that define runtime validation rules on DTOs.
Revision hook: TypeScript types protect you at compile time; class-validator and ValidationPipe protect you at runtime — you need both.
Q2. What is the role of class-transformer in the NestJS validation pipeline?
Short answer: class-transformer converts a plain JavaScript object, such as an incoming request body, into an actual instance of a DTO class using its plainToInstance function. This step is necessary because class-validator's decorator-based rules can only be checked against real class instances, not plain objects.
Detailed explanation: CreateUserDto now carries real runtime validation rules: name must be a non-empty string, email must be a validly formatted email address, password must be a string of at least 8 characters, and age, if provided, must be an integer of at least 13. Once ValidationPipe is registered globally in main.ts with whitelist, forbidNonWhitelisted, and transform all enabled, every request body across the entire application is automatically checked against its corresponding DTO's rules. A request missing a required email, or sending an unexpected extra field, is rejected automatically with a clear 400 Bad Request response, with zero manual validation code written inside any controller.
Practical example: Fintech and payment APIs use strict validation, often combined with forbidNonWhitelisted, to ensure no unexpected or potentially malicious extra fields slip into sensitive requests like fund transfers.
Interview tip: class-transformer converts plain objects into DTO class instances so those validation rules can actually be checked.
Revision hook: Validation decorators do nothing on their own until ValidationPipe is registered to actually enforce them.
Q3. How do you enable automatic validation across an entire NestJS application?
Short answer: You register NestJS's built-in ValidationPipe globally in main.ts using app.useGlobalPipes(new ValidationPipe()), which ensures every incoming request body is automatically validated against its corresponding DTO's class-validator rules before reaching any route handler.
Detailed explanation: class-validator and class-transformer work together with NestJS's built-in ValidationPipe to bring genuine runtime enforcement to DTOs that TypeScript's compile-time types alone cannot provide. class-validator decorators like @IsEmail(), @IsNotEmpty(), and @MinLength() attach validation rules directly to DTO properties, class-transformer converts incoming plain JSON into real DTO class instances so those rules can be checked, and ValidationPipe, once registered globally in main.ts, automatically validates every incoming request body and rejects invalid ones with a clear 400 Bad Request response. Configuration options like whitelist and forbidNonWhitelisted add an extra layer of protection against unexpected or malicious extra fields, making this trio a standard, essential part of virtually every production NestJS application.
Practical example: Public APIs exposed to third-party developers rely heavily on automatic ValidationPipe error messages to give external developers immediate, clear feedback about malformed requests without needing custom error-handling code.
Interview tip: ValidationPipe ties both libraries together and must be registered (usually globally) to have any effect.
Revision hook: Enabling whitelist and forbidNonWhitelisted is considered a security best practice for production APIs.
Q4. What is the difference between the whitelist and forbidNonWhitelisted ValidationPipe options?
Short answer: whitelist: true silently strips any properties from the incoming data that are not explicitly declared in the DTO, allowing the request to proceed with only the recognized fields. forbidNonWhitelisted: true goes further, rejecting the entire request with an error if it contains any undeclared properties, rather than silently removing them.
Detailed explanation: TypeScript's type system is a compile-time tool. Once your NestJS application is compiled to JavaScript and running, there is no remaining trace of types like CreateUserDto enforcing that email must genuinely be a string, let alone a validly formatted email address. A malicious or simply buggy client could send { "email": 12345 } and, without runtime validation, this incorrect data would flow straight into your business logic. class-validator solves this by providing decorators you attach directly to DTO properties, describing runtime validation rules. For example, @IsEmail() on the email property ensures the value is a syntactically valid email address, @IsString() ensures a value is genuinely a string, @IsNotEmpty() ensures a required field was not left blank, and @MinLength(8) can enforce a minimum password length. These decorators do not run automatically on their own; they simply attach metadata to the DTO class, similar to how NestJS's own decorators work. This is where class-transformer and NestJS's ValidationPipe come in. When a request arrives, the incoming JSON body is initially just a plain JavaScript object, not an actual instance of your DTO class, meaning class-validator's decorator metadata is not automatically checked against it. class-transformer's plainToInstance function (used internally by ValidationPipe) converts this plain object into a real instance of the DTO class, at which point class-validator's validate function can inspect it against every decorator rule that was attached. NestJS ties all of this together automatically through its built-in ValidationPipe. Applying it globally, in main.ts using app.useGlobalPipes(new ValidationPipe()), ensures every incoming request body across your entire application is automatically transformed and validated against its corresponding DTO before the route handler even executes. If validation fails, NestJS automatically returns a 400 Bad Request response describing exactly which fields failed and why, without you writing a single line of manual validation logic in your controllers. Two particularly valuable ValidationPipe options are whitelist and forbidNonWhitelisted. Setting whitelist: true automatically strips out any properties sent by the client that are not explicitly declared in the DTO, protecting against unexpected or malicious extra fields. Setting forbidNonWhitelisted: true goes a step further, rejecting the entire request with an error if any undeclared properties are present, rather than silently stripping them, which is useful for stricter APIs that want to surface client-side mistakes immediately.
Practical example: E-commerce checkout flows validate deeply nested DTOs (an order containing an array of line items) using class-validator's nested validation support to ensure every item in the array also passes its own rules.
Interview tip: whitelist strips unknown fields silently; forbidNonWhitelisted rejects the request outright if unknown fields are present.
Revision hook: NestJS's automatic 400 Bad Request responses on validation failure eliminate the need for repetitive manual validation code in every controller.
NestJS Validation Class-validator MCQs and Practice Questions
1. Which library provides decorators like @IsEmail() and @IsNotEmpty() for NestJS DTOs?
- class-transformer
- class-validator
- reflect-metadata
- rxjs
Answer: B. class-validator
Explanation: class-validator is the library responsible for providing decorators that define runtime validation rules on DTO class properties.
Concept link: class-validator provides decorators (like @IsEmail, @IsNotEmpty) that define runtime validation rules on DTOs.
Why this matters: TypeScript types protect you at compile time; class-validator and ValidationPipe protect you at runtime — you need both.
2. What NestJS mechanism automatically validates request bodies against a DTO's rules?
- Guards
- Interceptors
- ValidationPipe
- Middleware
Answer: C. ValidationPipe
Explanation: ValidationPipe is NestJS's built-in mechanism that automatically transforms and validates incoming request data against a DTO's class-validator decorators before it reaches the route handler.
Concept link: class-transformer converts plain objects into DTO class instances so those validation rules can actually be checked.
Why this matters: Validation decorators do nothing on their own until ValidationPipe is registered to actually enforce them.
3. What does setting whitelist: true in ValidationPipe do?
- Rejects all requests
- Automatically strips properties not defined in the DTO
- Disables validation entirely
- Converts all fields to strings
Answer: B. Automatically strips properties not defined in the DTO
Explanation: The whitelist option removes any incoming properties that are not explicitly declared on the target DTO class, helping prevent unexpected or unwanted data from passing through.
Concept link: ValidationPipe ties both libraries together and must be registered (usually globally) to have any effect.
Why this matters: Enabling whitelist and forbidNonWhitelisted is considered a security best practice for production APIs.
4. What HTTP status code does NestJS return by default when validation fails?
- 500 Internal Server Error
- 401 Unauthorized
- 400 Bad Request
- 404 Not Found
Answer: C. 400 Bad Request
Explanation: When ValidationPipe detects that incoming data fails one or more class-validator rules, NestJS automatically responds with a 400 Bad Request status along with details about which validations failed.
Concept link: whitelist strips unknown fields silently; forbidNonWhitelisted rejects the request outright if unknown fields are present.
Why this matters: NestJS's automatic 400 Bad Request responses on validation failure eliminate the need for repetitive manual validation code in every controller.
Common NestJS Validation Class-validator Mistakes to Avoid
- Adding class-validator decorators to a DTO but forgetting to register ValidationPipe globally, meaning the decorators are never actually enforced.
- Defining DTOs as plain interfaces, which silently breaks validation since class-validator decorators cannot attach to interfaces.
- Forgetting to set transform: true in ValidationPipe, which can lead to route parameters and query values not being automatically converted to their expected types.
- Assuming whitelist alone prevents malicious extra data; without forbidNonWhitelisted, unexpected fields are silently dropped rather than flagged, which may hide client-side bugs.
NestJS Validation Class-validator: Interview Notes and Exam Tips
- class-validator provides decorators (like @IsEmail, @IsNotEmpty) that define runtime validation rules on DTOs.
- class-transformer converts plain objects into DTO class instances so those validation rules can actually be checked.
- ValidationPipe ties both libraries together and must be registered (usually globally) to have any effect.
- whitelist strips unknown fields silently; forbidNonWhitelisted rejects the request outright if unknown fields are present.
Key NestJS Validation Class-validator Takeaways
- TypeScript types protect you at compile time; class-validator and ValidationPipe protect you at runtime — you need both.
- Validation decorators do nothing on their own until ValidationPipe is registered to actually enforce them.
- Enabling whitelist and forbidNonWhitelisted is considered a security best practice for production APIs.
- NestJS's automatic 400 Bad Request responses on validation failure eliminate the need for repetitive manual validation code in every controller.
NestJS Validation Class-validator: Summary
class-validator and class-transformer work together with NestJS's built-in ValidationPipe to bring genuine runtime enforcement to DTOs that TypeScript's compile-time types alone cannot provide. class-validator decorators like @IsEmail(), @IsNotEmpty(), and @MinLength() attach validation rules directly to DTO properties, class-transformer converts incoming plain JSON into real DTO class instances so those rules can be checked, and ValidationPipe, once registered globally in main.ts, automatically validates every incoming request body and rejects invalid ones with a clear 400 Bad Request response. Configuration options like whitelist and forbidNonWhitelisted add an extra layer of protection against unexpected or malicious extra fields, making this trio a standard, essential part of virtually every production NestJS application.