Awesome-omni-skill migrating-json-schemas
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.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/backend/migrating-json-schemas" ~/.claude/skills/diegosouzapw-awesome-omni-skill-migrating-json-schemas && rm -rf "$T"
skills/backend/migrating-json-schemas/SKILL.mdMigrating 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
or$schema
/id
usage).$id - Set the target version on the validator:
import ZSchema from 'z-schema'; const validator = ZSchema.create({ version: 'draft2020-12' }); - Run
to surface incompatibilities.validator.validateSchema(schema) - 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 |
|---|---|---|
| | draft-06 |
| | draft-2019-09 |
Array-form (tuple) | | draft-2020-12 |
| (when present) | draft-2020-12 |
(boolean) | | draft-06 |
(boolean) | | draft-06 |
(string arrays) | | draft-2019-09 |
(schema values) | | draft-2019-09 |
/ | / | 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
to id$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
to numericexclusiveMaximum
// 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
to definitions$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
to itemsprefixItems
// 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
declaration$schema
{ "$schema": "https://json-schema.org/draft/2020-12/schema" }
Draft-07 → Draft-2020-12
Smaller jump. Main changes:
→definitions
(and update$defs
paths)$ref- Array-form
→itemsprefixItems
→additionalItems
(whenitems
present)prefixItems
→dependencies
/dependentRequireddependentSchemas- Consider adopting
/unevaluatedProperties
for stricter validation of combined schemasunevaluatedItems
Draft-2019-09 → Draft-2020-12
Minimal changes:
- Array-form
→items
,prefixItems
→additionalItemsitems
/$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 data validator.validate(knownGoodData, migratedSchema); // Test with known-bad data const { 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