Skip to main content
Practice Problems

How to create and use custom decorators in NestJS?

Custom Decorators in NestJS

NestJS extensively uses TypeScript decorators for metadata-driven development. You can create your own decorators to reduce boilerplate and add reusable behavior.


Types of Custom Decorators

1. Parameter Decorator

Extract data from the request:

typescript
import { createParamDecorator, ExecutionContext } from '@nestjs/common'; export const CurrentUser = createParamDecorator( (data: string, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); const user = request.user; return data ? user?.[data] : user; }, );

Usage:

typescript
@Controller('profile') export class ProfileController { @Get() getProfile(@CurrentUser() user: User) { return user; } @Get('email') getEmail(@CurrentUser('email') email: string) { return { email }; } }

2. Metadata Decorator with SetMetadata

typescript
import { SetMetadata } from '@nestjs/common'; export const Roles = (...roles: string[]) => SetMetadata('roles', roles); export const Public = () => SetMetadata('isPublic', true);

Used with Guards:

typescript
@Controller('admin') export class AdminController { @Get('dashboard') @Roles('admin', 'superadmin') getDashboard() { return { message: 'Admin dashboard' }; } @Get('health') @Public() healthCheck() { return { status: 'ok' }; } }

3. Composed Decorator

Combine multiple decorators into one:

typescript
import { applyDecorators, UseGuards, SetMetadata } from '@nestjs/common'; import { ApiBearerAuth, ApiUnauthorizedResponse } from '@nestjs/swagger'; export function Auth(...roles: string[]) { return applyDecorators( SetMetadata('roles', roles), UseGuards(JwtAuthGuard, RolesGuard), ApiBearerAuth(), ApiUnauthorizedResponse({ description: 'Unauthorized' }), ); }

Usage — clean and DRY:

typescript
@Controller('users') export class UsersController { @Get() @Auth('admin') findAll() { return this.usersService.findAll(); } }

4. Class Decorator

typescript
import { Controller, UseInterceptors } from '@nestjs/common'; export function ApiController(prefix: string) { return applyDecorators( Controller(`api/v1/${prefix}`), UseInterceptors(LoggingInterceptor), UseInterceptors(TransformInterceptor), ); }
typescript
@ApiController('users') export class UsersController { // All routes prefixed with /api/v1/users // LoggingInterceptor and TransformInterceptor applied }

5. Property Decorator (for Validation)

typescript
import { registerDecorator, ValidationOptions } from 'class-validator'; export function IsStrongPassword(validationOptions?: ValidationOptions) { return function (object: object, propertyName: string) { registerDecorator({ name: 'isStrongPassword', target: object.constructor, propertyName, options: validationOptions, validator: { validate(value: string) { return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).{8,}$/.test(value); }, defaultMessage() { return 'Password must contain uppercase, lowercase, number, and special character'; }, }, }); }; }

Summary

Decorator TypeUse CaseAPI
ParameterExtract request datacreateParamDecorator()
MetadataSet metadata for Guards/InterceptorsSetMetadata()
ComposedCombine multiple decoratorsapplyDecorators()
ClassApply to entire controller/classapplyDecorators()
PropertyCustom validation rulesregisterDecorator()

Best practice: Custom decorators are powerful for reducing boilerplate. Create @Auth(), @CurrentUser(), and @Public() decorators in every NestJS project — they're used constantly.

Short Answer

Interview ready
Premium

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

Finished reading?
Practice Problems