Filter, Sort & Paginate With @Query
Query Parameters
Read URL query-string values with the `@Query` decorator. Combine with pipes to coerce types.
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.
Typed Query Objects (Recommended)
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.