Built-in Pipes
NestJS ships a set of ready-made pipes that solve the most common transformation and validation chore: turning raw, always-string request inputs into the typed values your handlers actually want. Route parameters, query strings, and headers arrive as strings, so before you can treat id as a number or active as a boolean you must parse and validate it. The built-in Parse* pipes do exactly this — coercing the value, throwing a clean 400 Bad Request when it is malformed, and handing your handler a correctly typed argument. This page covers each built-in pipe, how to tune its error behavior, and how DefaultValuePipe supplies fallbacks for missing inputs.
The available built-in pipes
All of these are exported from @nestjs/common. Each one validates that the incoming value matches an expected shape and transforms it into the corresponding JavaScript type, otherwise it raises a BadRequestException.
| Pipe | Expected input | Produces | Throws on |
|---|---|---|---|
ParseIntPipe | numeric string | number (integer) | non-integer string |
ParseFloatPipe | numeric string | number (float) | non-numeric string |
ParseBoolPipe | "true"/"false"/"1"/"0" | boolean | anything else |
ParseUUIDPipe | UUID string | string (validated) | malformed UUID |
ParseArrayPipe | delimited string / array | Array<T> | invalid items |
ParseEnumPipe | enum member string | enum value | value not in enum |
DefaultValuePipe | any (incl. undefined) | original or fallback | never |
Parsing numbers, booleans, and UUIDs
Bind a pipe by passing it to the route-param decorator. Because the pipe runs before your method body, the parameter type annotation is honest — id really is a number by the time the handler runs.
import { Controller, Get, Param, ParseIntPipe, ParseUUIDPipe, ParseBoolPipe } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
// id is guaranteed to be a valid integer here
return { id, type: typeof id };
}
@Get('by-uuid/:id')
findByUuid(@Param('id', new ParseUUIDPipe({ version: '4' })) id: string) {
return { id };
}
@Get(':id/flag')
findFlag(@Param('id', ParseIntPipe) id: number, @Query('active', ParseBoolPipe) active: boolean) {
return { id, active };
}
}
You can pass either the pipe class (ParseIntPipe) — letting Nest instantiate it — or an instance (new ParseUUIDPipe(...)) when you need to configure options. A request to GET /users/42 yields a real number; a bad request fails fast.
Output:
GET /users/42 -> { "id": 42, "type": "number" }
GET /users/abc -> 400 { "statusCode": 400, "message": "Validation failed (numeric string is expected)", "error": "Bad Request" }
Note: don’t forget to import the pipe from
@nestjs/common. Binding a pipe at the parameter level scopes it precisely to that single argument, which is the most common and predictable usage.
Parsing arrays and enums
ParseArrayPipe splits a delimited query string (or validates an incoming array) and can validate each item against another pipe or a DTO type. ParseEnumPipe restricts a value to the members of a TypeScript enum.
import { Controller, Get, Query, ParseArrayPipe, ParseEnumPipe } from '@nestjs/common';
enum SortOrder {
Asc = 'asc',
Desc = 'desc',
}
@Controller('products')
export class ProductsController {
@Get()
list(
@Query('ids', new ParseArrayPipe({ items: Number, separator: ',' })) ids: number[],
@Query('order', new ParseEnumPipe(SortOrder)) order: SortOrder,
) {
return { ids, order };
}
}
Output:
GET /products?ids=1,2,3&order=desc -> { "ids": [1, 2, 3], "order": "desc" }
GET /products?ids=1,x,3&order=desc -> 400 "ids must be an array of numbers..."
GET /products?ids=1,2,3&order=up -> 400 "order has an invalid value"
Configuring the error status code
By default every Parse* pipe throws a BadRequestException (HTTP 400). Sometimes a different status is more appropriate — for example, returning 404 Not Found when a malformed identifier should be treated as “no such resource”. Each pipe accepts an errorHttpStatusCode option, and an optional exceptionFactory for full control over the thrown error.
import { Controller, Get, Param, ParseIntPipe, HttpStatus, NotFoundException } from '@nestjs/common';
@Controller('articles')
export class ArticlesController {
@Get(':id')
findOne(
@Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_FOUND })) id: number,
) {
return { id };
}
@Get('strict/:id')
findStrict(
@Param(
'id',
new ParseIntPipe({
exceptionFactory: () => new NotFoundException('Article not found'),
}),
)
id: number,
) {
return { id };
}
}
Output:
GET /articles/abc -> 404 { "statusCode": 404, "message": "Validation failed (numeric string is expected)" }
GET /articles/strict/abc -> 404 { "statusCode": 404, "message": "Article not found", "error": "Not Found" }
Supplying fallbacks with DefaultValuePipe
Query parameters are frequently optional. If a client omits page or limit, the value arrives as undefined — and a Parse* pipe would reject it. DefaultValuePipe solves this by injecting a fallback before the parsing pipe runs, so the chain receives a valid value to coerce. Pipes execute left to right, which makes ordering essential.
import { Controller, Get, Query, DefaultValuePipe, ParseIntPipe, ParseBoolPipe } from '@nestjs/common';
@Controller('search')
export class SearchController {
@Get()
search(
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
@Query('limit', new DefaultValuePipe(20), ParseIntPipe) limit: number,
@Query('verbose', new DefaultValuePipe(false), ParseBoolPipe) verbose: boolean,
) {
return { page, limit, verbose };
}
}
Output:
GET /search -> { "page": 1, "limit": 20, "verbose": false }
GET /search?page=3&limit=50 -> { "page": 3, "limit": 50, "verbose": false }
Tip: always place
DefaultValuePipefirst in the pipe list. If you putParseIntPipeahead of it, the parser receivesundefinedand throws before the default is ever applied.
Best Practices
- Bind
Parse*pipes at the parameter level so each input is validated exactly where it is used, keeping type annotations truthful. - Pair
DefaultValuePipewith a parsing pipe for every optional query parameter, and always list it first in the chain. - Use
errorHttpStatusCodeorexceptionFactoryto return semantically correct status codes (e.g.404for malformed resource IDs). - Prefer
ParseUUIDPipewith an explicitversionover hand-rolled regex checks for identifier validation. - Use
ParseEnumPipeto constrain string inputs to known enum members instead of validating withifbranches inside the handler. - Reach for built-in pipes for primitive coercion; use a validation pipe with DTOs and class-validator for structured request bodies.