Skill v1.0.1
currentAutomated scan100/1001 files
version: "1.0.1" name: migrating-json-schemas description: Migrates JSON Schemas between draft versions for use with z-schema. Use when the user wants to upgrade schemas from draft-04 to draft-2020-12, convert between draft formats, update deprecated keywords, replace id with $id, convert definitions to $defs, migrate items to prefixItems, replace dependencies with dependentRequired or dependentSchemas, adopt unevaluatedProperties or unevaluatedItems, or adapt schemas to newer JSON Schema features.
Migrating JSON Schemas Between Drafts
z-schema supports draft-04, draft-06, draft-07, draft-2019-09, and draft-2020-12. This skill covers migrating schemas between drafts and verifying them with z-schema.
Migration workflow
- Identify the source draft (check
$schemaorid/$idusage). - Set the target version on the validator:
``typescript import ZSchema from 'z-schema'; const validator = ZSchema.create({ version: 'draft2020-12' }); ``
- Run
validator.validateSchema(schema)to surface incompatibilities. - Fix each reported error using the keyword mapping below.
- Re-validate until the schema passes.
Quick reference: keyword changes
| Old keyword (draft-04) | New keyword (draft-2020-12) | Introduced in | |
|---|---|---|---|
id | $id | draft-06 | |
definitions | $defs | draft-2019-09 | |
Array-form items (tuple) | prefixItems | draft-2020-12 | |
additionalItems | items (when prefixItems present) | draft-2020-12 | |
exclusiveMinimum: true (boolean) | exclusiveMinimum: <number> | draft-06 | |
exclusiveMaximum: true (boolean) | exclusiveMaximum: <number> | draft-06 | |
dependencies (string arrays) | dependentRequired | draft-2019-09 | |
dependencies (schema values) | dependentSchemas | draft-2019-09 | |
$recursiveRef / $recursiveAnchor | $dynamicRef / $dynamicAnchor | draft-2020-12 |
For the complete keyword mapping with examples, see references/keyword-mapping.md.
Common migration paths
Draft-04 → Draft-2020-12
This is the largest jump. Apply changes in order:
1. Rename `id` to `$id`
// Before (draft-04){ "id": "http://example.com/person.json", "type": "object" }// After (draft-2020-12){ "$id": "http://example.com/person.json", "type": "object" }
2. Convert boolean `exclusiveMinimum`/`exclusiveMaximum` to numeric
// Before (draft-04){ "type": "number", "minimum": 0, "exclusiveMinimum": true }// After (draft-2020-12){ "type": "number", "exclusiveMinimum": 0 }
Note: the minimum keyword is removed when converting to exclusiveMinimum as a number, since exclusiveMinimum: 0 means "greater than 0".
3. Rename `definitions` to `$defs`
// Before{ "definitions": { "address": { "type": "object" } } }// After{ "$defs": { "address": { "type": "object" } } }
Update all $ref values that point to #/definitions/... → #/$defs/....
4. Split `dependencies`
// Before (draft-04) — mixed dependencies{"dependencies": {"billing_address": ["credit_card"],"credit_card": { "type": "object", "properties": { "cvv": { "type": "string" } } }}}// After (draft-2020-12) — split into two keywords{"dependentRequired": {"billing_address": ["credit_card"]},"dependentSchemas": {"credit_card": { "type": "object", "properties": { "cvv": { "type": "string" } } }}}
5. Convert tuple `items` to `prefixItems`
// Before (draft-04){"type": "array","items": [{ "type": "string" }, { "type": "number" }],"additionalItems": false}// After (draft-2020-12){"type": "array","prefixItems": [{ "type": "string" }, { "type": "number" }],"items": false}
When items was an array (tuple validation), it becomes prefixItems. The old additionalItems becomes items.
6. Add `$schema` declaration
{ "$schema": "https://json-schema.org/draft/2020-12/schema" }
Draft-07 → Draft-2020-12
Smaller jump. Main changes:
definitions→$defs(and update$refpaths)- Array-form
items→prefixItems additionalItems→items(whenprefixItemspresent)dependencies→dependentRequired/dependentSchemas- Consider adopting
unevaluatedProperties/unevaluatedItemsfor stricter validation of combined schemas
Draft-2019-09 → Draft-2020-12
Minimal changes:
- Array-form
items→prefixItems,additionalItems→items $recursiveRef/$recursiveAnchor→$dynamicRef/$dynamicAnchor
Verifying a migrated schema
After migration, validate the schema itself against the target draft's meta-schema:
import ZSchema from 'z-schema';const validator = ZSchema.create({ version: 'draft2020-12' });try {validator.validateSchema(migratedSchema);console.log('Schema is valid for draft-2020-12');} catch (err) {console.log('Schema issues:', err.details);}
Then test data validation to confirm behavior is unchanged:
// Test with known-good datavalidator.validate(knownGoodData, migratedSchema);// Test with known-bad dataconst { valid } = validator.validateSafe(knownBadData, migratedSchema);if (valid) {console.warn('Migration issue: previously invalid data now passes');}
Backward compatibility
If schemas must work across multiple draft versions, use version: 'none' and set $schema in each schema to declare its own draft:
const validator = ZSchema.create({ version: 'none' });
Reference files
- references/keyword-mapping.md — Complete keyword mapping across all drafts with before/after examples