NestJS Custom Decorators
Custom decorators reduce boilerplate—extracting the current user from a request, or attaching roles metadata. This lesson covers parameter decorators and metadata decorators.
Parameter Decorators With createParamDecorator createParamDecorator builds decorators like @CurrentUser() that read from ExecutionContext and supply a value to a handler parameter, keeping controllers free of req.user casting.
export const CurrentUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);
@Get('me')
me(@CurrentUser() user: AuthUser) {
return user;
} After an auth guard attaches request.user, @CurrentUser() exposes it as a typed argument.
Metadata Decorators With SetMetadata export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
@Roles('admin')
@Delete(':id')
remove() {} Parameter decorators extract request data; metadata decorators annotate handlers for guards/interceptors. Read metadata with Reflector inside guards. Keep decorator factories small and composable. Document custom decorators so teams use them consistently. Custom Decorator Cheatsheet Two decorator styles in Nest.
Style API Use Param createParamDecorator Inject derived request values Metadata SetMetadata Mark routes for guards/filters Combine applyDecorators Compose multiple decorators Read meta Reflector Consume metadata in guards
Composing Decorators applyDecorators packages common combinations (@Auth() = JwtAuthGuard + Roles) into one readable decorator for controllers.
export function Auth(...roles: string[]) {
return applyDecorators(UseGuards(JwtAuthGuard, RolesGuard), Roles(...roles));
} Works Beyond HTTP Parameter decorators can switch on context type to support GraphQL context users as well as HTTP requests.
Common Mistakes Reading request.user in many controllers instead of a shared @CurrentUser() decorator. Forgetting Reflector when writing a RolesGuard that expects metadata. Building huge decorators that hide important security behavior. Not typing the value returned by a param decorator. Key Takeaways createParamDecorator builds clean parameter extractors. SetMetadata + Reflector power declarative guards. applyDecorators composes common auth/role stacks. Custom decorators improve readability when used consistently.
Pro Tip
Create an @Auth() composed decorator for protected routes so controllers declare intent in one place instead of repeating guard lists.
NestJS Dynamic Modules Go to next item