Skip to content
This repository was archived by the owner on Aug 27, 2025. It is now read-only.

fix(deps): update dependency zod-openapi to v5 - #15

Open
renovate[bot] wants to merge 2 commits into
masterfrom
renovate/zod-openapi-5.x
Open

fix(deps): update dependency zod-openapi to v5#15
renovate[bot] wants to merge 2 commits into
masterfrom
renovate/zod-openapi-5.x

Conversation

@renovate

@renovate renovate Bot commented Jul 5, 2025

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
zod-openapi ^4.2.4 -> ^5.0.0 age confidence

Release Notes

samchungy/zod-openapi (zod-openapi)

v5.0.0

Compare Source

zod-openapi v5 📚

This guide explains the key changes between zod-openapi v4 and v5.

You can migrate most of the way with our codemod:

pnpmx codemod-zod-openapi-v5 'src/**/*.ts'

npx codemod-zod-openapi-v5 'src/**/*.ts'

You can see the code here: codemod-zod-openapi-v5.

🔄 Differences from v4

🛠️ Runtime Changes

Using native Zod metadata

Zod v4 introduces a native .meta() method for metadata, eliminating the need for runtime extensions:

  • No more runtime monkey-patching
  • Removed: extendZodWithOpenApi(z) and import zod-openapi/extend
### Replace all schema definitions:
- z.string().openapi({ ... })
+ z.string().meta({ ... })

💡 Build-time optimization: You can now declare zod-openapi as a dev dependency if you create your schemas at build time.

⚠️ New requirements

  1. Zod v4 (3.25.74) required

    - import { z } from 'zod';
    + import * as z from 'zod/v4';
  2. Node v20+ required

    • Support for Node v18 has been dropped
📊 Schema Generation Changes

The internal schema generation has been completely replaced with Zod's native toJSONSchema() method. This should result in an overall performance improvement.

However, this will result in some changes to how some schemas are generated. Please raise a GitHub issue if you find any significant discrepancies.

🆕 OpenAPI version requirements

  • OpenAPI 3.1.0 is now the minimum required version
  • Support for OpenAPI 3.1.1 has been added

Lazy schemas supported natively

Zod automatically creates lazy components, so you can use z.lazy() without any additional configuration. It is still recommended to provide an id for lazy schemas.

🔄 Component references renamed: refid

- .openapi({ ref: 'MySchema' })
+ .meta({ id: 'MySchema' })

Wherever you previously used ref to create components within parameters, request objects and responses, has been replaced with id for consistency with Zod's syntax.

📝 Input & Output Schema Generation

Zod's native toJSONSchema() handles object schemas differently than our previous implementation:

  • 📥 Input schemas: Allow additional properties by default (no additionalProperties specified)
  • 📤 Output schemas: Strip extra properties (additionalProperties: false)

This better aligns with how Zod objects actually works, where input schemas are more permissive and output schemas are stricter and allows for structured outputs for AI applications.

As a result, when a schema containing a zod object with an ID is used in both request and response contexts, the library automatically generates two separate component schemas to properly represent the different behaviors.

How it works:

  1. Register a schema with an ID:
const schema = z
  .object({
    name: z.string(),
    age: z.number(),
  })
  .meta({
    id: 'Person',
  });
  1. When used in both contexts, it automatically generates:
components: {
  schemas: {
    Person: {
      type: 'object',
      properties: {
        name: { type: 'string' },
        age: { type: 'number' },
      },
    },
    PersonOutput: {
      type: 'object',
      properties: {
        name: { type: 'string' },
        age: { type: 'number' },
      },
      additionalProperties: false,
    },
  },
}

Customization options:

  • Custom output name: .meta({ id: 'Person', outputId: 'CustomOutputName' })
  • Global suffix: Set outputIdSuffix in CreateDocumentOptions to change from default "Output"

In certain cases, the same component can be used for both input and output contexts. This happens when the schemas are identical - for example, with primitive types like z.string().meta({ id: 'SimpleString'}). The library performs an equality check between input and output representations to determine when a single schema can be safely reused for both contexts.

For object schemas, you can explicitly control this behavior by using z.looseObject() (which allows additional properties) or z.strictObject() (which forbids them) instead of the standard z.object().

⚠️ Limitation: If your schema contains dynamically created lazy components, they won't be reused between input and output schemas.

Minor change: Manual schema generation

Previously, unsupported Zod schemas without a type field would throw an error. Now, any schema with fields will be accepted.

You can modify this behavior with the new allowEmptySchema option (see New Options below).

Minor change: .extend() behavior

  • No longer creates an embedded allOf referenced schema
  • This functionality would need to be contributed to the main Zod library if desired
🔧 Zod OpenAPI Options
🔁 Renamed Options

🔄 refTypeunusedIO

❌ Removed Options

⚙️ effectType

Transforms are not introspectable. effectType was introduced to attempt to address this and to try and keep the transform locked to the same type as the input schema.
For transform operations, use Zod's native .overwrite() method, wrap your schema in a .pipe(), or declare a manual type.

🔄 unionOneOf
🔄 enforceDiscriminatedUnionComponents
🔄 defaultDateSchema

These options are replaced by the new override system (see below)

🛠️ New Override System

Direct property setting:

This is native to Zod v4 and allows you to set properties directly on the schema.

z.date().meta({
  type: 'string',
  format: 'date-time',
});

Note: Zod's native type representation takes precedence over the fields set in the meta() method.
You can provide an override object or function to override this behavior.

Simple example:

z.string().meta({
  override: {
    type: number,
  },
});

Advanced customization with functions:

// Example: achieving unionOneOf behavior
z.union([z.string(), z.number()]).meta({
  override: ({ jsonSchema }) => {
    jsonSchema.oneOf = jsonSchema.anyOf;
    delete jsonSchema.anyOf;
  },
});

Global overrides:

import { createDocument } from 'zod-openapi';

createDocument(document, {
  override: ({ jsonSchema, zodSchema, io }) => {
    const def = zodSchema._zod.def;
    if (def.type === 'date' && io === 'output') {
      jsonSchema.type = 'string';
      jsonSchema.format = 'date-time';
    }
    if (def.type === 'union') {
      jsonSchema.oneOf = jsonSchema.anyOf;
      delete jsonSchema.anyOf;
    }
  },
});

Important: Only an override function can be provided in CreateDocumentOptions. Schema-level override will always run after the global function.

✨ New Options

🔄 cycles, reused

These options are passed directly to Zod's toJSONSchema() method to control how cycles and reused schemas are handled.

See Zod's JSON Schema documentation for details.

🧩 allowEmptySchema

Controls when empty schemas can be created. This controls if zod-openapi will throw an error when an empty schema is encountered.

  • { [zodType]: true } — Allow for both input and output
  • { [zodType]: { input: true, output: true } } — Allow for both input and output
  • { [zodType]: { input: true } } — Allow for input only
  • { [zodType]: { output: true } } — Allow for output only
🔁 Changed Options

🔄 refTypeunusedIO

Renamed to better reflect its purpose: specifying how unused component schemas should be rendered.

📋 Create Schema Options

🔄 schemaTypeio

Renamed to align with Zod's native terminology.

🔄 componentRefPathschemaComponentRefPath

Renamed for clarity and consistency.

🔄 componentsschemaComponents

Renamed for clarity and consistency.

🧩 New Components

PathItems, SecuritySchemes, Links, and Examples can now be created as reusable components

🔌 zod-openapi/api Changes

See ./api.md for detailed API changes in v5.


Configuration

📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
earthapp-mantle 220fec2 Jul 05 2025, 05:02 PM

@renovate

renovate Bot commented Jul 5, 2025

Copy link
Copy Markdown
Contributor Author

Edited/Blocked Notification

Renovate will not automatically rebase this PR, because it does not recognize the last commit author and assumes somebody else may have edited the PR.

You can manually request rebase by checking the rebase/retry box above.

⚠️ Warning: custom changes will be lost.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant