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
$schema
or
id
/
$id
usage).
Set the target version on the validator:
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:
/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 $ref paths) Array-form items → prefixItems additionalItems → items (when prefixItems present) dependencies → dependentRequired / dependentSchemas Consider adopting unevaluatedProperties / unevaluatedItems for 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 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