Query parameters are the standard way to support filtering, pagination, and sorting on list endpoints. This lesson covers @Query() and how to validate query parameters with a dedicated DTO.
Reading Query Parameters
Query parameters appear after a ? in the URL, like /cats?limit=10&page=2. The @Query() decorator extracts them individually by name, or as a single object containing every query parameter.
Just like route parameters, individual query parameters always arrive as strings and must be converted explicitly for numeric comparisons or database queries.
@Query('name') extracts a single query parameter as a string.
@Query() with no argument returns an object of every query parameter.
Pairing @Query() with a DTO and ValidationPipe validates and transforms query parameters together.
Query parameters are always optional from the framework's perspective, mark required ones explicitly in your DTO's validation rules.
Query Parameters Cheatsheet
Common patterns for reading and validating query strings.
Usage
Result
@Query('limit') limit: string
A single query parameter
@Query() query: any
All query parameters as one object
@Query('limit', ParseIntPipe) limit: number
Query parameter parsed as a number
@Query() dto: FindCatsQueryDto
Validated query object using a DTO class
A Realistic Pagination Example
Combining a query DTO with class-validator decorators and class-transformer lets you validate and convert pagination parameters in one pass, rejecting invalid input before it ever reaches your service layer.
import { Type } from 'class-transformer';
import { IsInt, IsOptional, Min } from 'class-validator';
export class PaginationQueryDto {
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
page: number = 1;
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
limit: number = 20;
}
@Type(() => Number) (from class-transformer) converts the incoming string query value to a number before class-validator checks it with @IsInt().
Array and Boolean Query Parameters
Query strings don't have a native array or boolean type, both Express and Nest use conventions, repeated keys (?tag=a&tag=b) become an array, and string values like "true"/"false" need explicit conversion with ParseBoolPipe or a transform decorator.
Common Mistakes
Comparing a numeric-looking query string directly to a number without converting it first.
Not providing sensible defaults for optional pagination parameters like page and limit.
Allowing unbounded limit values, letting a client request an enormous page size.
Forgetting that repeated query keys need explicit array handling, not just a single string.
Key Takeaways
@Query() extracts query string parameters individually or as a full object.
Query parameters always arrive as strings and often need explicit conversion.
A dedicated query DTO combined with ValidationPipe validates and transforms parameters together.
Always cap and default pagination-related query parameters to avoid abuse.
Pro Tip
Always set a maximum allowed limit in your pagination DTO validation (e.g. @Max(100)), otherwise a client can request ?limit=1000000 and put unexpected load on your database.
You now know how to handle query parameters safely. Next, learn how to read the Request Body for creating and updating resources.