Import JSON Schema
Understand which JSON Schema types, formats, and structures map cleanly to a Model on import — and which need extra handling.
Purpose
See a sample JSON Schema that exercises every type, format, and structure currently supported when importing a JSON Schema to create a Model, and understand the current limitations so you don't design a schema around constructs that won't carry over.
Background
JSON Schema is imported via Models > Import Model, selecting JSON Schema as the Import Type, providing either a File or a JSON Payload. The top-level schema object and everything listed under $defs (or definitions) are each imported as their own Model, so a single schema file can define several reusable Models at once.
On the review step before import, models with critical issues are marked with a red error and will not be imported; models with incomplete information are marked with a yellow warning but will still be imported. Malformed schemas, or schemas with missing $ref dependencies, can produce these errors.
Example
The following schema exercises all of the currently supported types, formats, and structures in a single import:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Numeric Types",
"description": "Definitions for unsigned, signed, and floating-point numeric types.",
"type": "object",
"$defs": {
"Status": {
"type": "object",
"title": "Status",
"description": "Reusable status model",
"properties": {
"code": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 0, "description": "Unsigned 16-bit status code (0 to 65535)" },
"message": { "type": "string", "default": "", "description": "Human-readable status message" },
"active": { "type": "boolean", "default": false, "description": "Whether the status is currently active" },
"details": {
"type": "object",
"title": "StatusDetails",
"description": "Detailed status breakdown",
"properties": {
"severity": { "type": "string", "default": "info", "description": "Severity level of the status (e.g. info, warning, error)" },
"count": { "type": "integer", "minimum": 0, "maximum": 4294967295, "default": 0, "description": "Unsigned 32-bit occurrence count (0 to 4294967295)" },
"ratio": { "type": "number", "minimum": -3.4028235e+38, "maximum": 3.4028235e+38, "default": 0.0, "description": "32-bit floating-point ratio value" }
}
}
}
}
},
"properties": {
"Uint8": { "type": "integer", "minimum": 0, "maximum": 255, "default": 0, "description": "Unsigned 8-bit integer (0 to 255)" },
"Uint16": { "type": "integer", "minimum": 0, "maximum": 65535, "default": 0, "description": "Unsigned 16-bit integer (0 to 65535)" },
"Uint32": { "type": "integer", "minimum": 0, "maximum": 4294967295, "default": 0, "description": "Unsigned 32-bit integer (0 to 4294967295)" },
"Uint64": { "type": "integer", "minimum": 0, "maximum": 18446744073709551615, "default": 0, "description": "Unsigned 64-bit integer (0 to 18446744073709551615)" },
"Int8": { "type": "integer", "minimum": -128, "maximum": 127, "default": 0, "description": "Signed 8-bit integer (-128 to 127)" },
"Int16": { "type": "integer", "minimum": -32768, "maximum": 32767, "default": 0, "description": "Signed 16-bit integer (-32768 to 32767)" },
"Int32": { "type": "integer", "minimum": -2147483648, "maximum": 2147483647, "default": 0, "description": "Signed 32-bit integer (-2147483648 to 2147483647)" },
"Int64": { "type": "integer", "minimum": -9223372036854775808, "maximum": 9223372036854775807, "default": 0, "description": "Signed 64-bit integer (-9223372036854775808 to 9223372036854775807)" },
"Real32": { "type": "number", "minimum": -3.4028235e+38, "maximum": 3.4028235e+38, "default": 0.0, "description": "32-bit floating-point number (IEEE 754 single precision)" },
"Real64": { "type": "number", "minimum": -1.7976931348623157e+308, "maximum": 1.7976931348623157e+308, "default": 0.0, "description": "64-bit floating-point number (IEEE 754 double precision)" },
"Bool": { "type": "boolean", "default": false, "description": "Boolean true/false value" },
"String": { "type": "string", "default": "", "description": "UTF-8 string value" },
"StringWithPattern": {
"type": "string",
"pattern": "^[0-9]{4,}$",
"default": "1234",
"description": "Numeric string with 4 or more digits. Validate in instance expression: /^[0-9]{4,}$/.test(value)"
},
"StringUUID": {
"type": "string",
"format": "uuid",
"default": "00000000-0000-0000-0000-000000000000",
"description": "UUID string (any version, 8-4-4-4-12 hex format). Validate in instance expression: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)"
},
"StringDateTime": {
"type": "string",
"format": "date-time",
"default": "1970-01-01T00:00:00Z",
"description": "ISO 8601 date-time string (e.g. 2026-08-16T08:00:00Z)"
},
"StringURI": {
"type": "string",
"format": "uri",
"default": "https://example.com",
"description": "URI string. Validate in instance expression: /^[a-zA-Z][a-zA-Z0-9+\\-.]*:\\/\\/[^\\s\\/$.?#].[^\\s]*$/.test(value)"
},
"NestedObject": {
"type": "object",
"description": "Example nested object containing mixed property types",
"properties": {
"Uint8": { "type": "integer", "minimum": 0, "maximum": 255, "default": 0, "description": "Unsigned 8-bit integer (0 to 255)" },
"Bool": { "type": "boolean", "default": false, "description": "Boolean true/false value" },
"String": { "type": "string", "default": "", "description": "UTF-8 string value" },
"DeepNestedObject": {
"type": "object",
"description": "Example deeply nested object",
"properties": {
"Uint8": { "type": "integer", "minimum": 0, "maximum": 255, "default": 0, "description": "Unsigned 8-bit integer (0 to 255)" },
"Bool": { "type": "boolean", "default": false, "description": "Boolean true/false value" },
"String": { "type": "string", "default": "", "description": "UTF-8 string value" }
}
}
}
},
"NestedModel": {
"$ref": "#/$defs/Status",
"description": "Reference to the reusable Status model"
}
}
}
What imports and how it's typed
The property name is just a label — it's the combination of type, minimum/maximum, and format that determines the resulting attribute type.
Whole numbers ("type": "integer") — the minimum/maximum pair is matched against a fixed set of recognized ranges to pick the narrowest matching sized integer type:
| Recognized range | Resulting type |
|---|---|
| 0 to 255 | Uint8 |
| 0 to 65535 | Uint16 |
| 0 to 4294967295 | Uint32 |
| 0 to 18446744073709551615 | Uint64 |
| -128 to 127 | Int8 |
| -32768 to 32767 | Int16 |
| -2147483648 to 2147483647 | Int32 |
| -9223372036854775808 to 9223372036854775807 | Int64 |
Floating-point numbers ("type": "number") — matched the same way, against the IEEE 754 single- and double-precision bounds:
| Recognized range | Resulting type |
|---|---|
| -3.4028235e+38 to 3.4028235e+38 | Real32 |
| -1.7976931348623157e+308 to 1.7976931348623157e+308 | Real64 |
Other supported types and structures:
"type": "boolean"→ Bool"type": "string"→ String"type": "string", "format": "date-time"→ a native date-time type — this is the oneformatvalue currently mapped on import"type": "object"with nestedproperties→ a nested sub-object on the Model, at any depth (seeNestedObject/DeepNestedObjectabove)- An object under
$defs, referenced elsewhere via"$ref": "#/$defs/<name>"→ imported as its own reusable Model (seeStatus/NestedModelabove) - The top-level
title/descriptionare carried over as the resulting Model's name and description;descriptionon individual properties carries over the same way
Current limitations
A few JSON Schema constructs don't currently have an equivalent on import:
format: uriandformat: uuid— unlikedate-time, these aren't mapped to a dedicated type. The property still imports as a plain String with no format-level validation.pattern— a string's regexpatternconstraint is not carried over as an enforced validation either.- Nullable types (e.g. a JSON Schema union with
"null") are not supported. - Arrays (
"type": "array") are not supported. "type": "any"or multiple types (atypearray of more than one non-null type) are not supported.$refcannot point to an already-existing Model — it can only reference a definition included in the same schema being imported (i.e. under that schema's own$defs/definitions). If a nested model is meant to reuse a Model that already exists in the project, its definition still needs to be included in the JSON Schema you're importing, rather than referenced externally.
For the constructs above that aren't enforced on import (pattern, format: uri, format: uuid), populate description with the validation the property was meant to carry, phrased so it can be dropped straight into an Instance Expression — as StringWithPattern, StringUUID, and StringURI do in the example above. This keeps the intent of the original schema visible and actionable, even though Intelligence Hub won't enforce it automatically.
Additional Considerations
Instance Expressions as the general workaround
Since instance Expressions run basic JavaScript, they can reproduce most validation a JSON Schema might otherwise express — regex tests (pattern, format: uri, format: uuid), range checks, or cross-attribute conditions — even where the schema construct itself doesn't import as an enforced rule.
Last updated: 2026-08-25