
NestJS has many decorators, but beginners usually confuse two groups: decorators on classes, such as @Controller() and @Injectable(), and decorators on methods, such as @Get() and @Post().
The short rule:
- Class decorators decide what role the class plays.
- Method decorators decide how a method is used by the framework.
- Parameter decorators decide where method arguments come from.
Three levels
Common NestJS decorators map to three levels:
- class decorators
- method decorators
- parameter decorators
These levels match a request flow: which controller handles the route, which method handles the request, and how request data enters method parameters.
Class decorators
Class decorators attach metadata to the whole class:
import { Controller, Injectable } from "@nestjs/common"
@Controller("users")
export class UserController {}
@Injectable()
export class UserService {}
Common class decorator roles:
- mark a controller
- mark a provider or service
- mark a module
@Controller("users") tells Nest that the class handles routes under the users prefix. @Injectable() tells Nest the class can participate in dependency injection.
Method decorators
Method decorators describe how a method participates in routing or request handling:
import { Controller, Get, Post } from "@nestjs/common"
@Controller("users")
export class UserController {
@Get()
findAll() {
return "all users"
}
@Post()
create() {
return "created"
}
}
Common examples:
@Get()@Post()@Put()@Delete()@UseGuards()@UseInterceptors()
The class decorator gives the building. The method decorator gives the specific door.
Parameter decorators
@Body(), @Param(), and @Query() are parameter-level decorators:
@Get(":id")
findOne(@Param("id") id: string) {
return id
}
They do not map a method to a route. They tell Nest how to extract request data for that method parameter.
Request flow
request enters
-> @Controller() matches controller prefix
-> @Get() / @Post() matches method route
-> @Param() / @Body() extracts data
-> controller method runs
-> controller calls service marked with @Injectable()
This explains why @Injectable() and @Get() are not the same kind of decorator. One registers an injectable class. The other declares a route handler.
Common confusion
@Controller() and @Get() are not alternatives. They work together:
@Controller("users"): class-level route prefix@Get(":id"): method-level HTTP route
@Injectable() does not turn methods into routes. It marks a class as a provider for dependency injection.
@UseGuards() can appear on a class or method. Decide based on scope: apply to the whole controller or only one endpoint.
Related FreeMac guides
- For scheduled tasks, read Cron Syntax: 5 Fields, 6 Fields, and NestJS Scheduling.
- For project config, read Front-End Config: Env, Node, Git, ESLint, and TypeScript.
- For reverse proxy deployment, read Nginx Reverse Proxy Guide: proxy_pass, Headers, WebSocket, and Logs.
Continue reading
Strapi 5 Populate Guide: Relations, Media, and Nested Queries
Use Strapi 5 REST populate correctly for relations, media, components, nested queries, field selection, qs query builders, and safer production response sizes.
12 min readStrapi 5 Getting Started: Content Models, APIs, and Permissions
Start a Strapi 5 project, choose between Collection Types, Single Types, Components, and Dynamic Zones, then publish content and verify REST API permissions.
10 minCron Syntax Guide: Expressions, Fields, and NestJS Examples
Understand 5-field and 6-field cron, common symbols, NestJS examples, time zones, and the scheduling mistakes caused by missing seconds or UTC assumptions.
Subscribe to FreeMac
Weekly picks: free Mac software reviews, trusted source updates, alternatives, and low-friction guides.