Skip to content

NestJS Request Object

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() Signature

@Get()
handler(@Req() req: Request) {
  // req.headers, req.cookies, req.ip, req.url, ...
}
  • @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.

@Get('download')
download(@Res() res: Response) {
  res.status(200).sendFile('/files/report.pdf');
}

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.