nest-zod
v1.0.0
Published
A library to provide helpers to validate and transform objects with Zod for NestJS.
Downloads
58
Maintainers
Readme
nest-zod
Zod-powered request validation, query/param parsing, and response serialization for NestJS.
Quick Start
Install the package and its required peers:
pnpm add nest-zod zod @nestjs/common rxjsIf you want Swagger / OpenAPI metadata too:
pnpm add @nestjs/swaggerChoose one import path:
nest-zod: runtime validation and serialization onlynest-zod/swagger: same runtime behavior, plus Swagger metadata
Most new users who already use @nestjs/swagger should start with nest-zod/swagger.
First Example
import { Controller, Get, Post } from '@nestjs/common';
import { z } from 'zod';
import { ZBody, ZParam, ZQuery, ZSerialize } from 'nest-zod/swagger';
const createItemSchema = z.object({
title: z.string().min(1),
});
const listItemsQuerySchema = z.object({
page: z.coerce.number().int().positive().default(1),
});
const itemResponseSchema = z.object({
id: z.uuid(),
title: z.string(),
});
type CreateItemDto = z.infer<typeof createItemSchema>;
type ListItemsQueryDto = z.infer<typeof listItemsQuerySchema>;
type ItemResponseDto = z.infer<typeof itemResponseSchema>;
@Controller('items')
export class ItemsController {
@Post()
@ZSerialize(itemResponseSchema)
create(@ZBody(createItemSchema) body: CreateItemDto): ItemResponseDto {
return {
id: '550e8400-e29b-41d4-a716-446655440000',
title: body.title,
};
}
@Get(':id')
@ZSerialize(itemResponseSchema)
get(@ZParam('id', z.uuid()) id: string): ItemResponseDto {
return {
id,
title: 'Widget',
};
}
@Get()
list(@ZQuery(listItemsQuerySchema) query: ListItemsQueryDto) {
return {
page: query.page,
items: [],
};
}
}What the decorators do:
ZBody,ZParam,ZQueryparse incoming values with ZodZSerializeencodes the handler return value with the schema before sending the response
No extra Nest registration is required for these decorators. They attach the needed validation pipe or serializer interceptor themselves, so you do not need APP_PIPE, APP_INTERCEPTOR, or useGlobalInterceptors() for nest-zod to work.
For query params, use:
ZQuery(schema)for the whole query objectZQuery('name', schema)for a named query parameter, including object-shaped values
Which Import Should I Use?
Use nest-zod when you only want runtime behavior:
import { ZBody, ZParam, ZQuery, ZSerialize } from 'nest-zod';Use nest-zod/swagger when you also want generated request/response metadata for SwaggerModule:
import { ZBody, ZParam, ZQuery, ZSerialize } from 'nest-zod/swagger';With nest-zod/swagger, ZSerialize documents the effective success status for the route:
200by default201for@Post()handlers unless overridden- an explicit
statusif you pass one toZSerialize(..., { status })
nest-zod/swagger also exports:
import {
isZodObjectSchema,
zodSchemaForEncodedResponse,
zodToOpenApiSchema,
} from 'nest-zod/swagger';Playground
This repo includes a small Nest app showing both variants:
- Swagger-backed routes under
/items - Runtime-only routes under
/plain-items
Run it locally:
pnpm install
pnpm run playground:startThen open:
- API:
http://localhost:3100 - Swagger UI:
http://localhost:3100/docs
Useful endpoints:
POST /itemsGET /itemsGET /items/named-query?filter[q]=widgetGET /items/:idPOST /plain-itemsGET /plain-items/:idGET /items/broken/serialization
The playground enables Express's extended query parser, so nested query values like
filter[q]=widget are parsed into objects before Zod validation runs.
For local iteration:
pnpm run playground:devDevelopment
pnpm install
pnpm run test
pnpm run build