NestJS abstracts most request data behind decorators like @Param() and @Body(), but sometimes you need the raw underlying request object. This lesson covers @Req() and when to reach for it.
Accessing the Raw Request
The @Req() decorator injects the platform-specific request object, an Express Request by default, or a Fastify request if you've switched platforms. It gives you access to headers, raw query strings, cookies, and anything else the underlying framework exposes.
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller('cats')
export class CatsController {
@Get()
findAll(@Req() request: Request) {
console.log(request.headers['user-agent']);
return 'all cats';
}
}
Importing the Request type from express gives you full autocomplete and type-checking on the raw request object, at the cost of coupling this handler to the Express platform.
@Req() gives you the full platform request object, unlike Nest's more specific decorators.
Using @Req() ties your handler to a specific platform (Express or Fastify).
Prefer specific decorators (@Param, @Query, @Body, @Headers) whenever they cover your need.
The equivalent @Res() decorator exists for the response object, with similar trade-offs.
Request-Related Decorators
Nest's decorators for pulling data out of an incoming request.
Decorator
Returns
@Req()
The full platform request object
@Headers('x-api-key')
A single request header, or all headers
@Ip()
The client's IP address
@HostParam()
A parameter extracted from the request's host/subdomain
@Session()
The session object, when session middleware is enabled
Why Avoid @Req() When Possible
Relying on @Req() couples your handler to the specific platform in use, and to Express/Fastify types, making the handler harder to test in isolation and harder to migrate between platforms. Nest's dedicated decorators (@Param, @Query, @Body) are platform-agnostic and easier to unit test, since you can pass plain values instead of constructing a mock request.
Combining @Req() and @Res()
When you use @Res() to take manual control of the response (for example, to stream a file), Nest disables its automatic response handling for that route by default, meaning you must call res.send() or similar yourself.
You can opt back into Nest's automatic handling for @Res() routes by passing { passthrough: true }: @Res({ passthrough: true }) res: Response.
Common Mistakes
Reaching for @Req() by default instead of a more specific, testable decorator.
Using @Res() to send a response and forgetting Nest no longer serializes the return value automatically.
Tightly coupling business logic to Express-specific request properties, hurting portability to Fastify.
Not typing the injected request object, losing autocomplete and type safety.
Key Takeaways
@Req() injects the full underlying platform request object.
Prefer specific decorators like @Param, @Query, and @Body for better testability and portability.
Using @Res() opts a handler out of Nest's automatic response handling unless passthrough: true is set.
Reaching for the raw request/response objects is sometimes necessary, but should be the exception, not the default.
Pro Tip
Before adding @Req() to a handler, check whether Nest already has a dedicated decorator for what you need, @Headers(), @Ip(), and @Session() cover most cases people reach for the raw request object for.
You now know how to access the raw request object when needed. Next, learn about Route Parameters using the @Param decorator.