This document tracks the Zod 4 surface that next-openapi-gen currently validates in code and fixtures.
The generator still relies primarily on static AST analysis, but it now uses a selective runtime-assisted Zod 4 export path for a small set of features where input/output-aware JSON Schema adds useful fidelity without replacing the existing AST converter.
| Zod 4 construct | Expected emitted shape | OpenAPI targets | Regression coverage | Notes |
|---|---|---|---|---|
z.email() |
type: "string", format: "email" |
3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts |
Same parity as z.string().email() |
z.url() |
type: "string", format: "uri" |
3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts |
Same parity as z.string().url() |
z.uuid() |
type: "string", format: "uuid" |
3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts |
Closes issue #92 |
z.iso.datetime() |
type: "string", format: "date-time" |
3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts |
Nested namespace helper support |
z.guid() / z.ipv4() / z.ipv6() / z.iso.duration() |
String formats are preserved in emitted schemas | 3.0, 3.1, 3.2 |
tests/unit/schema/zod/node-helpers.test.ts, tests/unit/schema/zod/zod-converter.test.ts |
Added to the AST converter parity path |
nullable() / nullish() on supported base schemas |
nullable: true in 3.0; type: [..., "null"] in 3.1+ |
3.0, 3.1, 3.2 |
tests/integration/generator/zod4-support.test.ts, tests/integration/validation/openapi-validation.test.ts |
Version finalization rewrites nullable semantics |
pipe() into a stronger schema |
Preserves strongest representable base schema | 3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts |
Used for patterns like z.string().pipe(z.email()) |
Runtime-assisted coerce / pipe variants |
Request-side schemas can keep input shapes while responses keep output constraints when the runtime export can prove the difference | 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts |
Falls back to AST behavior when runtime export is unavailable |
transform() / refine() / superRefine() / brand() |
Preserve the underlying JSON-schema-compatible base shape | 3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts |
Runtime-only semantics are not serialized |
Static .meta({...}) metadata |
Copies representable metadata such as example, examples, and deprecated into emitted schemas |
3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts |
Runtime path is used only for supported static metadata objects |
z.tuple([...]) |
Emits tuple-aware arrays with prefixItems, items: false, and fixed item counts |
3.1, 3.2 |
tests/unit/schema/zod/node-helpers.test.ts, tests/unit/schema/zod/zod-converter-helpers.test.ts |
3.0 downgrades happen in version finalization |
| Shared imported query schemas | Per-parameter schemas retain $ref / allOf detail |
3.0, 3.1, 3.2 |
tests/unit/schema/typescript/schema-content.test.ts, tests/integration/generator/zod4-support.test.ts |
Closes issue #93 |
Required fields in @queryParams object schemas |
Per-parameter required: true matches parent schema required list |
3.0, 3.1, 3.2 |
tests/unit/schema/typescript/schema-content.test.ts, tests/integration/generator/zod4-support.test.ts |
Closes issue #94 |
Exported z.infer<typeof Schema> aliases in pure-Zod mode |
No duplicate component unless alias is explicitly referenced | 3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts |
Closes issue #96 |
import { z } from "zod/v4" |
Parsed the same as zod import path when the local binding is z |
3.0, 3.1, 3.2 |
tests/unit/schema/zod/zod-converter.test.ts, tests/integration/generator/zod4-support.test.ts, tests/integration/generator/zod4-support.test.ts |
Also covered in a Pages Router fixture |
| Fixture | Purpose |
|---|---|
tests/fixtures/projects/next/app-router/zod-only-coverage |
App Router Zod-first coverage for top-level helpers, transformed query params, nullable helper output, and pure-Zod alias behavior |
tests/fixtures/projects/next/pages-router/zod-flow |
Pages Router coverage for zod/v4 imports and Zod-generated response schemas |
- The generator preserves the strongest OpenAPI-representable base schema for transforms and refinements, but it does not serialize arbitrary runtime predicates.
- The runtime-assisted Zod 4 export path is intentionally selective. It currently targets features such as
coerce,pipe,templateLiteral,stringbool, and static.meta(...)payloads, while the broader converter still runs through AST analysis. @authmetadata currently emits alternative security requirements for comma-separated values. Combined requirements and advanced scheme fields should still be modeled in templates or reusable OpenAPI fragments.- Response inference is selective and best-effort. It supports named response types, inline object responses, multiple return paths, and
204responses, but explicit@responsetags remain the most deterministic option when stable component names matter.