Specification scope: Core with the Import companion specification.
Two imported schemas can both define Address, and each can refer to its own
supporting definitions. Copying those declarations without namespaces and
rewritten pointers would make local type identity depend on import order.
An import processor prevents that ambiguity. It places copied types in a chosen namespace, rewrites their internal pointers, and gives local declarations deterministic precedence over imported names.
Two source documents
The first document publishes a root type and one supporting definition at
https://schemas.example.com/people.json:
{
"$schema": "https://json-structure.org/meta/core/v0/#",
"$id": "https://schemas.example.com/people.json",
"name": "Person",
"type": "object",
"properties": {
"name": { "type": "string" },
"address": { "type": { "$ref": "#/definitions/Address" } }
},
"required": ["name", "address"],
"definitions": {
"Address": {
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
}
}
}
The second is a definition library at
https://schemas.example.com/common.json:
{
"$schema": "https://json-structure.org/meta/core/v0/#",
"$id": "https://schemas.example.com/common.json",
"name": "CommonDocument",
"type": "object",
"definitions": {
"AuditStamp": {
"type": "object",
"properties": {
"createdBy": { "type": "string" },
"createdAt": { "type": "datetime" }
},
"required": ["createdBy", "createdAt"]
}
}
}
One consumer, two import modes
The consumer imports the complete people document and only the definitions from the common document:
{
"$schema": "https://json-structure.org/meta/extended/v0/#",
"$id": "https://schemas.example.com/customer-record.json",
"$uses": ["JSONStructureImport"],
"name": "CustomerRecord",
"type": "object",
"properties": {
"customer": {
"type": { "$ref": "#/definitions/People/Person" }
},
"audit": {
"type": { "$ref": "#/definitions/Common/AuditStamp" }
}
},
"required": ["customer", "audit"],
"definitions": {
"People": {
"$import": "https://schemas.example.com/people.json",
"Address": {
"type": "object",
"properties": {
"city": { "type": "string" },
"country": { "type": "string" }
},
"required": ["city", "country"]
}
},
"Common": {
"$importdefs": "https://schemas.example.com/common.json"
}
}
}
The extended meta-schema offers JSONStructureImport and enables it for its
own root import. The import draft, unlike the validation and conditional
drafts, introduces no competing $uses name; it makes the extension available
through the extended meta-schema. The explicit $uses above names the
repository feature so a reader can see the dependency at the point of use.
A matching instance is ordinary JSON:
{
"customer": {
"name": "Ada Lovelace",
"address": {
"city": "London",
"country": "GB"
}
},
"audit": {
"createdBy": "migration-7",
"createdAt": "2026-11-09T10:30:00Z"
}
}
$import copies the external root type as People/Person and copies its
definitions. $importdefs copies only the external definitions, so
Common/AuditStamp exists but Common/CommonDocument does not.
Placement supplies the namespace. An import at the schema root, or directly as
definitions.$import, targets the root namespace. An import inside
definitions.People targets People. Nested namespace objects can place it
deeper still.
Internal pointers stay internal
The source Person points to #/definitions/Address. This value is a JSON
Pointer into the source schema. During import, the processor prefixes it so it
resolves inside People, not against a consumer-level Address. The rewrite
also applies recursively through nested imports and to $ref, $extends, and $addins pointers.
Shadowing comes next. The local People/Address replaces the imported type of
the same name entirely; there is no merge and no route back to the replaced
version. Consequently the imported Person.address resolves to the local
replacement requiring both city and country.
That precedence is deterministic, but blunt. Put both versions under different namespaces when both must survive.
URI resolution is not package lookup
The import draft requires absolute URI values and RFC 3986/RFC 3987 resolution. It defines no npm-style package search, filesystem fallback, registry alias, or version selection. Processors must fetch and validate the target as a schema; the draft also requires safeguards against circular or excessively deep chains.
Repository samples sometimes use relative paths for local development. Those are useful fixtures, but they conflict with the draft’s absolute-URI requirement. The complete documents above follow the draft.