Bird
Raised Fist0
NestJSframework~8 mins

Custom validation decorators in NestJS - Performance & Optimization

Choose your learning style10 modes available
Performance: Custom validation decorators
MEDIUM IMPACT
This affects the runtime validation speed during request processing and can impact server response time and user experience.
Validating user input with custom decorators
NestJS
import { registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';

@ValidatorConstraint({ async: true })
export class IsUniqueEmailConstraint implements ValidatorConstraintInterface {
  private cache = new Set<string>();

  async validate(email: string) {
    if (this.cache.has(email)) return true; // Cached result
    // Simulate fast async check
    const isUnique = email !== 'taken@example.com';
    if (isUnique) this.cache.add(email);
    return isUnique;
  }
}

export function IsUniqueEmail(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: IsUniqueEmailConstraint,
      async: true
    });
  };
}
Caches validation results to avoid repeated slow checks, reducing validation time and improving request responsiveness.
📈 Performance GainReduces average validation time from 1000ms to near 0ms on repeated inputs, improving INP significantly.
Validating user input with custom decorators
NestJS
import { registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';

@ValidatorConstraint({ async: true })
export class IsUniqueEmailConstraint implements ValidatorConstraintInterface {
  validate(email: string) {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(email !== 'taken@example.com');
      }, 1000); // Simulates slow async check
    });
  }
}

export function IsUniqueEmail(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: IsUniqueEmailConstraint,
      async: true
    });
  };
}
The validation runs a slow asynchronous check with a 1-second delay on every input, blocking request processing and increasing response time.
📉 Performance CostBlocks request processing for 1000ms per validation, increasing INP and server response time.
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
Slow async validation with delayN/A (server-side)N/AN/A[X] Bad
Cached fast validation logicN/A (server-side)N/AN/A[OK] Good
Rendering Pipeline
Custom validation decorators run during request validation before controller logic executes, affecting server-side processing time and response delivery.
→Request Processing
→Validation Logic
→Response Generation
⚠️ BottleneckValidation Logic stage when decorators perform slow or blocking operations
Core Web Vital Affected
INP
This affects the runtime validation speed during request processing and can impact server response time and user experience.
Optimization Tips
1Avoid long blocking operations inside custom validation decorators.
2Cache validation results when possible to speed up repeated checks.
3Keep validation logic lightweight to improve server response and user input responsiveness.
Performance Quiz - 3 Questions
Test your performance knowledge
What is the main performance risk of using slow asynchronous operations inside custom validation decorators?
AThey block request processing and increase server response time
BThey increase browser paint time
CThey cause layout shifts on the page
DThey increase CSS selector complexity
DevTools: Network and Performance panels
How to check: Use the Network panel to measure request duration and the Performance panel to profile server response time and validation delays.
What to look for: Look for long request times and blocking periods during validation phase indicating slow custom decorators.

Practice

(1/5)
1. What is the main purpose of creating a custom validation decorator in NestJS?
easy
A. To create new routes in the application
B. To automatically generate database schemas
C. To handle HTTP requests and responses
D. To define your own rules for validating data inputs

Solution

  1. Step 1: Understand validation decorators

    Validation decorators in NestJS are used to check if data meets certain rules before processing.
  2. Step 2: Purpose of custom validation decorators

    Custom validation decorators let you create your own specific rules that are not covered by built-in validators.
  3. Final Answer:

    To define your own rules for validating data inputs -> Option D
  4. Quick Check:

    Custom validation decorators = custom data rules [OK]
Hint: Custom decorators create your own data validation rules [OK]
Common Mistakes:
  • Confusing validation decorators with routing or database features
  • Thinking custom decorators generate schemas automatically
  • Assuming they handle HTTP requests directly
2. Which of the following is the correct way to start defining a custom validator class in NestJS?
easy
A. Use @Injectable decorator on the class
B. Use @Controller decorator on the class
C. Use @ValidatorConstraint decorator on the class
D. Use @Module decorator on the class

Solution

  1. Step 1: Identify the decorator for custom validators

    In NestJS, custom validation classes must be marked with @ValidatorConstraint to tell the system they are validators.
  2. Step 2: Differentiate from other decorators

    @Controller is for routing, @Injectable for services, and @Module for modules, not for validation.
  3. Final Answer:

    Use @ValidatorConstraint decorator on the class -> Option C
  4. Quick Check:

    @ValidatorConstraint marks custom validator classes [OK]
Hint: Custom validators use @ValidatorConstraint decorator [OK]
Common Mistakes:
  • Using @Controller or @Module instead of @ValidatorConstraint
  • Forgetting to decorate the validator class
  • Confusing service decorators with validation decorators
3. Given this custom validator code snippet, what will be the output when validating the value "abc123"?
import { ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';

@ValidatorConstraint({ name: 'isAlphaOnly', async: false })
export class IsAlphaOnly implements ValidatorConstraintInterface {
  validate(text: string) {
    return /^[A-Za-z]+$/.test(text);
  }
  defaultMessage() {
    return 'Text must contain only letters';
  }
}
medium
A. Validation fails because 'abc123' contains numbers
B. Validation passes because 'abc123' contains letters
C. Validation passes because regex allows numbers
D. Validation throws an error due to syntax

Solution

  1. Step 1: Analyze the regex in validate method

    The regex /^[A-Za-z]+$/ matches only strings with letters from start to end, no numbers allowed.
  2. Step 2: Check the test string 'abc123'

    This string contains numbers '123', so it does not match the regex and validate returns false.
  3. Final Answer:

    Validation fails because 'abc123' contains numbers -> Option A
  4. Quick Check:

    Regex /^[A-Za-z]+$/ rejects numbers [OK]
Hint: Check regex carefully to see what characters it allows [OK]
Common Mistakes:
  • Assuming partial matches pass validation
  • Ignoring numbers in the test string
  • Thinking regex allows digits when it does not
4. Identify the error in this custom validation decorator code:
import { registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';

@ValidatorConstraint({ async: true })
export class IsEvenNumber implements ValidatorConstraintInterface {
  validate(value: number) {
    return value % 2 === 0;
  }
}

export function IsEven(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      name: 'isEven',
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      validator: IsEvenNumber,
    });
  };
}
medium
A. The validate method should return a Promise because async is true
B. The registerDecorator call is missing the validate method
C. The decorator function should not accept validationOptions
D. The class should not have @ValidatorConstraint decorator

Solution

  1. Step 1: Check async flag and validate method

    The @ValidatorConstraint decorator has async: true, so validate must return a Promise<boolean>.
  2. Step 2: Validate method returns boolean, not Promise

    Currently, validate returns a boolean directly, which conflicts with async: true.
  3. Final Answer:

    The validate method should return a Promise because async is true -> Option A
  4. Quick Check:

    async: true requires Promise return [OK]
Hint: If async: true, validate must return Promise<boolean> [OK]
Common Mistakes:
  • Returning boolean instead of Promise when async is true
  • Omitting @ValidatorConstraint decorator
  • Misusing registerDecorator parameters
5. You want to create a custom validation decorator that checks if a string property contains at least one uppercase letter and one digit. Which approach correctly combines the concepts to implement this in NestJS?
hard
A. Use built-in decorators @IsUppercase and @IsNumber together on the property
B. Create a class with @ValidatorConstraint, implement validate() using regex, then use registerDecorator in a function to apply it
C. Create a service with @Injectable and call it inside the DTO without decorators
D. Use only registerDecorator with a simple function without a class or @ValidatorConstraint

Solution

  1. Step 1: Understand custom validation structure

    Custom validators require a class decorated with @ValidatorConstraint implementing validate() method.
  2. Step 2: Use registerDecorator to link the class to a decorator function

    This function applies the validator to the property in the DTO.
  3. Step 3: Implement validate() with regex checking uppercase and digit presence

    This ensures the string meets both conditions in one check.
  4. Final Answer:

    Create a class with @ValidatorConstraint, implement validate() using regex, then use registerDecorator in a function to apply it -> Option B
  5. Quick Check:

    Custom validator class + registerDecorator function = correct approach [OK]
Hint: Combine @ValidatorConstraint class with registerDecorator function [OK]
Common Mistakes:
  • Skipping the validator class and using only registerDecorator
  • Trying to use services instead of decorators for validation
  • Assuming built-in decorators cover combined conditions
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard