Blog
Wild & Free Tools

Zod vs class-validator for NestJS Validation (2026)

Last updated: April 2026 7 min read

Table of Contents

  1. NestJS Default: class-validator with ValidationPipe
  2. Using Zod in NestJS with a Custom Pipe
  3. Side-by-Side Comparison
  4. When to Choose Each
  5. Frequently Asked Questions

class-validator is the NestJS default — it uses decorators on DTO classes and integrates with the built-in ValidationPipe. Zod works in NestJS via a custom pipe but requires more setup. For greenfield projects that prioritize TypeScript type inference and plain-object validation, Zod is worth the extra setup. For teams following NestJS conventions, class-validator fits naturally.

This guide covers both approaches with working code so you can make an informed decision.

NestJS Default: class-validator with ValidationPipe

The standard NestJS validation setup:

npm install class-validator class-transformer
// main.ts
app.useGlobalPipes(new ValidationPipe({ transform: true }));
// create-user.dto.ts
import { IsEmail, IsString, MinLength, IsOptional, IsNumber } from 'class-validator';

export class CreateUserDto {
  @IsString()
  @MinLength(2)
  name: string;

  @IsEmail()
  email: string;

  @IsNumber()
  @IsOptional()
  age?: number;
}

This is the NestJS-documented approach, and most NestJS tutorials use it. The decorators are readable and colocated with the DTO definition.

Using Zod in NestJS with a Custom Pipe

npm install zod
// zod-validation.pipe.ts
import { PipeTransform, BadRequestException } from '@nestjs/common';
import { ZodSchema } from 'zod';

export class ZodValidationPipe implements PipeTransform {
  constructor(private schema: ZodSchema) {}

  transform(value: unknown) {
    const result = this.schema.safeParse(value);
    if (!result.success) {
      throw new BadRequestException(result.error.flatten().fieldErrors);
    }
    return result.data;
  }
}
// users.controller.ts
import { z } from 'zod';

const CreateUserSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
  age: z.number().optional()
});

@Post()
@UsePipes(new ZodValidationPipe(CreateUserSchema))
create(@Body() dto: z.infer<typeof CreateUserSchema>) {
  return this.usersService.create(dto);
}
Sell Custom Apparel — We Handle Printing & Free Shipping

Side-by-Side Comparison

Factorclass-validatorZod
NestJS integrationNative (ValidationPipe)Custom pipe needed
SyntaxClass decoratorsFunctional API
TypeScript inferenceRequires separate interfacez.infer automatic
Plain object supportNo (requires class instance)Yes
Reuse across layersHarder (class-specific)Easy (schema = type)
CommunityNestJS standardGrowing in NestJS
Testingclass-transformer requiredDirect object testing

When to Choose Each

Choose class-validator when:

Choose Zod when:

To generate a base Zod schema from a sample request body, paste the JSON into the JSON to Zod converter.

Try It Free — No Signup Required

Runs 100% in your browser. No data is collected, stored, or sent anywhere.

Open Free JSON to Zod Converter

Frequently Asked Questions

Should I use Zod or class-validator in NestJS?

Both work. class-validator integrates natively with NestJS ValidationPipe and follows the official docs. Zod requires a custom pipe but provides better TypeScript inference and works with plain objects. For new projects, either is fine — pick based on your team's TypeScript preferences.

Can I use Zod with the NestJS ValidationPipe?

Not directly. NestJS ValidationPipe is built for class-validator. To use Zod, create a ZodValidationPipe class that implements PipeTransform and calls schema.safeParse() internally.

Can I mix Zod and class-validator in the same NestJS project?

Yes. You can use class-validator for most DTOs (via ValidationPipe) and Zod for specific cases where you need better inference or shared schemas. Apply the ZodValidationPipe per-route where needed.

How do I generate a Zod schema for a NestJS DTO?

Paste a sample request body JSON into the free converter at /developer-tools/json-to-zod/. Copy the generated schema, add NestJS-appropriate constraints (.email(), .min(), .optional()), and use it with the ZodValidationPipe.

Launch Your Own Clothing Brand — No Inventory, No Risk