Specification scope: Core with the Import companion specification.

An imported declaration does not remain a live cross-document reference. A JSON Structure processor fetches the external schema, copies its types into the importing document’s definitions, rewrites their internal references, and treats the result as local.

The published declaration remains the source that authors maintain. Consumers of the processed schema see a local type library with deterministic names. The processor, not the schema author, performs the copy and reference rewriting.

Start with the published type

Suppose the postal team publishes this schema at https://schemas.example.com/postal-address.json:

{
  "$schema": "https://json-structure.org/meta/core/v0/#",
  "$id": "https://schemas.example.com/postal-address.json",
  "name": "PostalAddress",
  "type": "object",
  "properties": {
    "street": { "type": "string" },
    "city": { "type": "string" },
    "postalCode": {
      "type": { "$ref": "#/definitions/PostalCode" }
    }
  },
  "required": ["street", "city", "postalCode"],
  "definitions": {
    "PostalCode": {
      "type": "string",
      "maxLength": 12
    }
  }
}

The root declares PostalAddress, and its definitions section contributes the reusable PostalCode type.

Bring both into a namespace

An order schema can import the complete document into a local Postal namespace:

{
  "$schema": "https://json-structure.org/meta/extended/v0/#",
  "$id": "https://schemas.example.com/order.json",
  "type": "object",
  "properties": {
    "orderId": { "type": "uuid" },
    "shipTo": {
      "type": { "$ref": "#/definitions/Postal/PostalAddress" }
    }
  },
  "required": ["orderId", "shipTo"],
  "definitions": {
    "Postal": {
      "$import": "https://schemas.example.com/postal-address.json"
    }
  }
}

$import brings in the external root type and its definitions. After processing, Postal/PostalAddress and Postal/PostalCode behave as local reusable types. The processor prefixes cross-references inside the imported material with the local namespace. PostalAddress therefore still reaches the imported PostalCode, even if the importing schema declares another type with that short name.

Processors handle imports before other schema keywords. One schema may import several documents into separate local namespaces.

Leave the root behind with $importdefs

Sometimes the external document’s root describes a message you do not need, while its definitions section is the useful library. Replace the import with:

{
  "definitions": {
    "Postal": {
      "$importdefs": "https://schemas.example.com/postal-address.json"
    }
  }
}

Now #/definitions/Postal/PostalCode exists, but #/definitions/Postal/PostalAddress does not. $importdefs has the same merge and namespace behavior as $import; its only difference is that it omits the external root type.

Choose $import when the published root belongs in the local contract. Choose $importdefs when only the external type library is relevant.

The URI is the import reference

The values of $import and $importdefs must be absolute URIs. Processors resolve those URIs. The import specification defines no package-name search, filesystem convention, registry protocol, or fallback rule.

A processor must resolve the URI and verify that the result is a schema document. The specification’s security considerations recommend caching remote documents and using secure transport. They require processors to detect and mitigate circular or excessively deep import chains. A local cache may satisfy the request, but the schema still contains the same import URI.

Shadowing replaces; it does not merge

A local declaration with the same name in the same namespace replaces the imported declaration entirely:

{
  "definitions": {
    "Postal": {
      "$import": "https://schemas.example.com/postal-address.json",
      "PostalCode": {
        "type": "string",
        "maxLength": 8
      }
    }
  }
}

The local Postal/PostalCode wins. It does not merge with the imported type, and the shadowing declaration cannot refer back to the imported type it replaced.

Shadowing is blunt. It can adapt an imported library, and it can also redirect every imported cross-reference to the replacement. Use another local name when both versions must remain available.

Authors maintain one published declaration. Processors turn each import into a local library with deterministic pointers and no external type references left to resolve.