nestjs-zod: one Zod schema for request validation, DTOs, serialization and OpenAPI
All NestJS + Zod utilities you need
At a glance
- What is it?
- nestjs-zod is an MIT licensed TypeScript library that wires Zod into NestJS through a validation pipe, a serialization interceptor and a helper for building DTOs from schemas, so one schema can drive runtime validation, response shaping and OpenAPI output. It is aimed at NestJS teams tired of keeping validation rules and documentation in step.
- Who is it for?
- nestjs-zod fits a NestJS team that already uses Zod for its domain schemas and wants the same schemas to produce request validation, response serialization and OpenAPI output, and the codemod removes most of the wiring work on the way in.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 10 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The duplication problem: validation rules and documentation written twice
NestJS applications tend to accumulate two parallel descriptions of the same data. One lives in a DTO class, with decorators that tell the framework what to check and what to document. The other lives in the OpenAPI document, which is often generated from those same decorators or written by hand. When the two drift apart, the API contract and the implementation disagree, and the failure shows up as a request that passes validation and then breaks deeper in the handler, or as documentation that promises a field the server never returns.
nestjs-zod attacks that duplication by making Zod the single source. The README lists the core features: create nestjs DTOs from zod schemas, validate and parse request body, query params and url params using zod, serialize response bodies using zod, automatically generate OpenAPI documentation using zod, and support for zod codecs.
That last group of features is the point. The same schema object is consulted at four different moments: when a request arrives, when a DTO type is needed, when a response leaves, and when the OpenAPI document is assembled. If a field changes, one edit propagates, because there is only one object to edit.
The audience is NestJS developers, and the README's own description of the package is all NestJS plus Zod utilities you need. The topics attached to the repository include nestjs, nest, node, nodejs, zod, openapi and typescript, which describes the territory accurately. This is a bridge library for a specific framework pairing, not a general validation package, and it makes no attempt to be one.
The project is a pnpm workspace monorepo, with packages/ at the top level, a pnpm-workspace.yaml file and an example application under packages/example/ that the README points to for a full integration example.
A pipe for input, an interceptor for output, and a filter for errors
The mechanism is three NestJS extension points, each doing one job.
ZodValidationPipe is the input side. The README states that it is required in order to validate the request body, query and params, and it is registered globally as an APP_PIPE so that it applies to every route rather than being attached by hand. Because it is a Nest pipe, it runs before the handler body, so a request that fails the schema never reaches your controller code.
ZodSerializerInterceptor is the output side. The README says it is required in order to validate the response bodies, and it is registered as an APP_INTERCEPTOR. This is the part that is unusual in a NestJS stack. A serializer that validates outgoing bodies is a second line of defence: if a handler returns an object that does not match the declared schema, the interceptor catches the discrepancy rather than the client receiving a malformed payload.
The third piece is an HttpExceptionFilter, and the README marks it optional. Its job is custom handling for Zod errors, and the example in the documentation shows a filter extending BaseExceptionFilter that checks for ZodSerializationException, pulls the ZodError out of it, logs the Zod error message, and then delegates to the parent implementation. The point of the pattern is that a serialization failure and a client validation failure are different kinds of event, and the filter is where you decide that a serialization failure is a server bug worth a log line rather than a 400.
The documentation index in the README also names the supporting types: createZodDto for turning a schema into a DTO, createZodValidationPipe and createZodSerializerInterceptor for building custom variants, ZodValidationException and ZodSchemaDeclarationException for error signalling, and ZodSerializerDto for setting a schema on a response.
Automatic setup with a codemod, then the manual wiring
There are two ways in, and the automatic one is unusual enough to be worth describing first.
The README's Automatic Setup section gives a single command that runs a codemod against an existing project:
npx nestjs-zod-cli /path/to/nestjs/projectThe command adds the validation pipe, the serialization interceptor, the http exception filter and the swagger cleanup function. That is the whole set of wiring steps, applied to your project directory. For a codebase that already has a hand-rolled version of some of this, the codemod is also the fastest way to see what the library expects the module to look like.
The manual path is the fallback, and it is worth reading even if you use the codemod, because the codemod's output is easier to reason about when you know what it did.
The package install is a single npm command, and the note on the same line matters because Zod is a peer dependency rather than something the library vendors:
npm install nestjs-zod # Note: zod ^3.25.0 || ^4.0.0 is also requiredThe supported Zod range is therefore version 3.25 or later, or version 4, and the README lists support for zod codecs as a core feature. The dual range is a real constraint for anyone pinning Zod in a monorepo: a project on Zod 3.24 or earlier cannot use this library, and the 3.25 floor exists so that the 3.x and 4.x APIs line up.
The manual steps then add ZodValidationPipe to the AppModule as an APP_PIPE provider, add ZodSerializerInterceptor as an APP_INTERCEPTOR, optionally add the HttpExceptionFilter as an APP_FILTER, and optionally add cleanupOpenApiDoc. The README marks the first two as required and the last two as optional, and flags the OpenAPI step as important if you use @nestjs/swagger.
cleanupOpenApiDoc is not optional when you publish Swagger docs
The OpenAPI side deserves its own look, because it is the part most likely to be skipped and the part most likely to produce a wrong document.
The README describes cleanupOpenApiDoc as required if using @nestjs/swagger to properly post-process the OpenAPI document, and the change it makes is at the point where the document is handed to the Swagger module. Without it, the setup call receives the document as assembled; with it, the document is post-processed first. The step is marked optional in the setup checklist but marked important in the callout, which is a fair summary of how it behaves in practice: an application will not crash without it, and will simply publish a document that does not match the schemas.
The reason is the shape of the generated output. Zod schemas carry their own descriptions and structure, and the OpenAPI document built from them needs post-processing to line up with what the routes actually accept and return. A schema-derived document is a different artifact from a decorator-derived one, and the post-processing step is the bridge between the two.
The practical consequence is that if you are a team already publishing Swagger documentation, adopting this library means changing that documentation pipeline, not just adding validation. The document your clients read will be generated from your Zod schemas instead of from decorators, and the shape of the resulting spec, including how required and optional fields appear, follows from the schemas rather than from any annotation you wrote.
That is a genuine trade-off rather than a free win. If your published OpenAPI document is a contractual artefact that other teams code against, the switch is a change to a public interface, and the existing spec should be diffed against the generated one before the change ships. The README does not document how the generated document differs from a decorator-based one, so that diff is a step you have to do yourself.
Where the library stops, and what a decorator-based DTO approach does instead
Three limits are visible in the documentation.
The first is that the pipe and the interceptor are separate. Registering ZodValidationPipe gives you request validation. Response shaping only happens if ZodSerializerInterceptor is also registered, and the response schema has to be attached to the handler through ZodSerializerDto. A team that adds the pipe, tests that bad requests are rejected, and declares victory will find that responses are still whatever the handler returned. Both registrations are in the README's manual steps, and the codemod adds both, so the failure mode is a partial manual setup rather than a library defect.
The second is the error handling. The http exception filter is optional, and without it the default Nest behaviour decides what a Zod failure looks like to a client. The README's example filter exists to show how to change that, and it shows the interesting case, a ZodSerializationException, which is a different class of problem from a ZodValidationException.
The third is that the project is tightly bound to a stack. Zod is required, NestJS is required, and the package is published as a scoped set of utilities rather than a general validation library. There is no path to a plain Express or Fastify application without Nest's dependency injection, since both the pipe and the interceptor are Nest constructs.
The real alternative is the approach nestjs-zod is displacing: defining DTOs as classes with decorators and letting the framework and @nestjs/swagger read those annotations. The difference in approach is where the truth lives. With classes, the validation rules and the documentation metadata are two sets of annotations on the same class, and they can disagree. With this library, the Zod schema is the definition, the DTO is derived from it, and the OpenAPI output is derived from the same object. The cost is that a team with an existing decorator-based DTO layer and a published spec is undertaking a migration rather than adding a library, and the repository keeps a MIGRATION.md file at the root for exactly that reason.
Release cadence, the monorepo layout and what MIT lets you do
On maintenance, the repository is not archived and the last push was on 2026-10-14, with the default branch named main. The recent tags are v5.5.0 from 2026-07-25, v5.4.0 from 2026-05-15 and v5.3.0 from 2026-04-05, so versions move every couple of months and the project is on a 5.x line.
The version number matters more here than it would in a small library, because a major bump of Zod is a supported upgrade path and a major bump of nestjs-zod is likely to be a migration. The MIGRATION.md file at the repository root is where those changes are recorded, and reading it is part of upgrading rather than an optional step. The tree also has CONTRIBUTING.md, CODE_OF_CONDUCT.md and FUNDING.yml, and the README notes that the project is sponsored by apisandbox.dev and has a GitHub Sponsors page.
The repository layout explains how the packages fit together. The root package.json is a private monorepo manifest named nestjs-zod-monorepo at version 0.0.1, with the real work happening in packages/ and the example application in packages/example/. The build tooling is pnpm, with pnpm-lock.yaml and pnpm-workspace.yaml at the root, and CI runs from a workflow named test-and-build.yml as the README badge shows.
The licence is MIT, which is the permissive end of the scale. You can use the package inside a commercial NestJS service, vendor it, modify it, and redistribute it, provided the copyright notice and permission notice are kept. There is no copyleft condition, so shipping a service built on it does not oblige you to open source your application, which is the usual reason a commercial team cares which of the two licence families a dependency falls into.
Editorial conclusion
nestjs-zod fits a NestJS team that already uses Zod for its domain schemas and wants the same schemas to produce request validation, response serialization and OpenAPI output, and the codemod removes most of the wiring work on the way in. It does not fit a team that has committed to class-based DTOs and decorator-based documentation, because the point of the library is to have one source of truth, and it does not fit a service that must run without Zod as a dependency, since zod itself is a required peer. Before you adopt it, read MIGRATION.md in the repository root, run the npx nestjs-zod-cli codemod against a branch rather than your main project, and confirm that the OpenAPI output still matches what you publish if you use @nestjs/swagger without cleanupOpenApiDoc.
Frequently asked questions
How do I set up nestjs-zod in an existing NestJS project?
The README's automatic setup runs a codemod that adds the validation pipe, serialization interceptor, http exception filter and swagger cleanup function: `npx nestjs-zod-cli /path/to/nestjs/project`. You can also wire the pieces manually in your AppModule.
Which versions of Zod does nestjs-zod support?
The install note in the README says zod ^3.25.0 || ^4.0.0 is also required, so Zod 3.25 or newer, or Zod 4, has to be present alongside the package.
Do I need to register the serializer interceptor separately from the validation pipe?
Yes. The README states that ZodValidationPipe is required to validate the request body, query and params, and that ZodSerializerInterceptor is required to validate the response bodies, so they are two separate registrations in the AppModule.
What does cleanupOpenApiDoc do in nestjs-zod?
It is the post-processing step for the OpenAPI document when you use @nestjs/swagger, applied where the document is passed to the Swagger module. The README marks it optional in the setup list but flags it as important if you use @nestjs/swagger.
How do I upgrade nestjs-zod to a new major version?
The repository keeps a MIGRATION.md file at the root for that purpose. Recent tags are v5.5.0 from 2026-07-25, v5.4.0 from 2026-05-15 and v5.3.0 from 2026-04-05, and the last push was on 2026-10-14.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/benlorantfy-nestjs-zod)Was this useful?