Skip to content
NestJS ns pipes 5 min read

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.

PipeExpected inputProducesThrows on
ParseIntPipenumeric stringnumber (integer)non-integer string
ParseFloatPipenumeric stringnumber (float)non-numeric string
ParseBoolPipe"true"/"false"/"1"/"0"booleananything else
ParseUUIDPipeUUID stringstring (validated)malformed UUID
ParseArrayPipedelimited string / arrayArray<T>invalid items
ParseEnumPipeenum member stringenum valuevalue not in enum
DefaultValuePipeany (incl. undefined)original or fallbacknever

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 DefaultValuePipe first in the pipe list. If you put ParseIntPipe ahead of it, the parser receives undefined and 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 DefaultValuePipe with a parsing pipe for every optional query parameter, and always list it first in the chain.
  • Use errorHttpStatusCode or exceptionFactory to return semantically correct status codes (e.g. 404 for malformed resource IDs).
  • Prefer ParseUUIDPipe with an explicit version over hand-rolled regex checks for identifier validation.
  • Use ParseEnumPipe to constrain string inputs to known enum members instead of validating with if branches inside the handler.
  • Reach for built-in pipes for primitive coercion; use a validation pipe with DTOs and class-validator for structured request bodies.
Last updated June 14, 2026
Was this helpful?