diff --git a/packages/zod/src/v4/classic/tests/to-json-schema.test.ts b/packages/zod/src/v4/classic/tests/to-json-schema.test.ts index 3397900456..58a12c2cf7 100644 --- a/packages/zod/src/v4/classic/tests/to-json-schema.test.ts +++ b/packages/zod/src/v4/classic/tests/to-json-schema.test.ts @@ -1535,6 +1535,52 @@ test("describe with id", () => { `); }); +test("override with id", () => { + const jobId = z.string().meta({ id: "jobIdFoo" }); + + const a = z.z.toJSONSchema( + z.object({ + current: jobId.describe("Current job"), + previous: jobId.describe("Previous job"), + }), + { + override(ctx) { + if (ctx.path.join("/") === "$defs/jobIdFoo") { + ctx.jsonSchema.id = "jobIdChanged"; + } + }, + } + ); + + expect(a).toMatchInlineSnapshot(` + { + "$defs": { + "jobIdFoo": { + "id": "jobIdChanged", + "type": "string", + }, + }, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "current": { + "$ref": "#/$defs/jobIdFoo", + "description": "Current job", + }, + "previous": { + "$ref": "#/$defs/jobIdFoo", + "description": "Previous job", + }, + }, + "required": [ + "current", + "previous", + ], + "type": "object", + } + `); +}); + test("overwrite id", () => { const jobId = z.string().meta({ id: "aaa" }); diff --git a/packages/zod/src/v4/core/to-json-schema.ts b/packages/zod/src/v4/core/to-json-schema.ts index 787c3a311c..96000c3641 100644 --- a/packages/zod/src/v4/core/to-json-schema.ts +++ b/packages/zod/src/v4/core/to-json-schema.ts @@ -817,9 +817,17 @@ export class JSONSchemaGenerator { // build defs object const defs: JSONSchema.BaseSchema["$defs"] = params.external?.defs ?? {}; + + const rootKey = this.target === "draft-2020-12" ? "$defs" : "definitions"; + for (const entry of this.seen.entries()) { const seen = entry[1]; if (seen.def && seen.defId) { + this.override({ + zodSchema: entry[0] as schemas.$ZodTypes, + jsonSchema: seen.def, + path: [rootKey, seen.defId], + }); defs[seen.defId] = seen.def; } }