Query Parameters

Filter, Sort & Paginate With @Query

Query Parameters

Read URL query-string values with the `@Query` decorator. Combine with pipes to coerce types.

4 min read Level 1/5 #nestjs#routing#query
What you'll learn
  • Read individual query values with `@Query('name')`
  • Read all queries as an object
  • Apply ParseIntPipe to coerce numbers

The query string — the ?limit=10&sort=name bit — is where filtering, sorting, and pagination live. @Query() pulls those values into your handler.

A Single Query Key

import { Controller, Get, Query } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get()
  list(@Query('limit') limit: string) {
    return { limit };
  }
}

GET /users?limit=20 lands limit === '20'. Like route params, query values arrive as strings.

The Whole Bag at Once

@Get()
list(@Query() q: Record<string, string>) {
  return q; // { limit: '20', sort: 'name' }
}

Useful for proxies that pass the query through unchanged.

Coerce With Pipes

Same trick as route params — apply a pipe to coerce:

import { ParseIntPipe } from '@nestjs/common';

@Get()
list(
  @Query('limit', new ParseIntPipe({ optional: true })) limit?: number,
  @Query('cursor') cursor?: string,
) {
  return { limit: limit ?? 25, cursor };
}

optional: true lets the request omit the param without 400-ing.

For anything non-trivial, build a DTO and let ValidationPipe validate the whole object:

import { IsInt, IsOptional, Min, IsIn } from 'class-validator';
import { Type } from 'class-transformer';

export class ListUsersQuery {
  @IsOptional() @Type(() => Number) @IsInt() @Min(1)
  limit?: number;

  @IsOptional() @IsIn(['asc', 'desc'])
  sort?: 'asc' | 'desc';
}
@Get()
list(@Query() q: ListUsersQuery) {
  return this.users.list(q);
}

With transform: true on your global ValidationPipe, q.limit arrives as a real number, not a string — and invalid input is rejected before the handler ever runs.

Arrays in Query Strings

By default Express parses ?tag=a&tag=b as tag: ['a', 'b']. Fastify needs explicit configuration. When in doubt, log the parsed query during development so you know what shape your handler is getting.

The Request Body →