Skip to content

protean schema

The protean schema command group generates and inspects JSON Schema (Draft 2020-12) documents for data-carrying domain elements: aggregates, entities, value objects, commands, events, and projections.

All commands accept either --domain (live domain module) or --ir (serialized IR file) as input.

Commands

Command Description
protean schema generate Generate JSON Schema files for all data-carrying elements
protean schema show Display the JSON Schema for a specific element
protean schema render Render index DDL artifacts (with --indexes)

protean schema generate

Generates JSON Schema files for every data-carrying element in the domain and writes them to the output directory.

# From a live domain
protean schema generate --domain=my_app.domain

# From a serialized IR file
protean schema generate --ir=domain-ir.json

# Custom output directory
protean schema generate --domain=my_app.domain --output=build

Options

Option Description Default
--domain, -d Path to the domain module (e.g. my_app.domain)
--ir Path to an IR JSON file
--output, -o Root output directory .protean
--format, -f Output format: json, avro, protobuf, or all json

Either --domain or --ir is required; they are mutually exclusive.

Formats. --format avro emits Avro {name}.v{version}.avsc records (null-first unions for optionals, so optional fields default to null; uuid/date/timestamp-millis logical types; nested value objects become named records referenced by fullname). --format protobuf emits proto3 {name}.v{version}.proto messages with optional/repeated labels, google.protobuf.Timestamp for dates, and field numbers assigned deterministically in sorted field-name order — so re-generating an unchanged schema is byte-identical. Adding a field renumbers alphabetically-later fields, so these numbers are for emission, not wire-compatible evolution. Both are compiler backends for schema emission; runtime binary encode/decode is out of scope, and field-level constraints (choices/enums, min/max) are not carried into either format.

--format all emits every format into one schemas/ tree in a single pass — JSON, Avro, and Protobuf files coexist per element (distinct extensions) rather than one clobbering the next. Together with protean events catalog, this is the local schema-registry on-ramp.

Output structure

Schemas are written to <output>/schemas/, grouped by aggregate cluster:

.protean/
├── ir.json
└── schemas/
    ├── Order/
    │   ├── aggregates/
    │   │   └── Order.v1.json
    │   ├── commands/
    │   │   └── PlaceOrder.v1.json
    │   ├── entities/
    │   │   └── LineItem.v1.json
    │   ├── events/
    │   │   └── OrderPlaced.v2.json
    │   └── value_objects/
    │       └── Money.v1.json
    └── projections/
        └── OrderDashboard.v1.json

Filenames include the element version for events and commands. Other elements default to v1. The schemas/ directory is cleared on each run to remove stale files.

The ir.json written alongside the schemas is a canonical baseline (the volatile generated_at timestamp is omitted), byte-identical to protean ir show --canonical, so a committed .protean/ir.json only changes when the domain contract changes.


protean schema show

Displays the JSON Schema for a single element, looked up by short name or fully qualified name (FQN).

# By short name
protean schema show OrderPlaced --domain=my_app.domain

# By FQN
protean schema show my_app.ordering.OrderPlaced --domain=my_app.domain

# Raw JSON (for piping)
protean schema show OrderPlaced --domain=my_app.domain --raw

# From an IR file
protean schema show OrderPlaced --ir=domain-ir.json --raw

With --raw, the JSON is written to stdout while logs go to stderr, so the output is safe to pipe (protean schema show ... --raw | jq).

Options

Option Description Default
--domain, -d Path to the domain module
--ir Path to an IR JSON file
--raw Output plain JSON without syntax highlighting false

Arguments

Argument Description
element Element short name (e.g. OrderPlaced) or FQN (e.g. app.OrderPlaced)

Disambiguation

If multiple elements share the same short name, the command lists all matching FQNs and asks you to use the full FQN:

Multiple elements match 'Order':
  ecommerce.ordering.Order
  ecommerce.shipping.Order

Use the full FQN to disambiguate.

protean schema render

Renders the index declarations on a domain's aggregates and entities to per-dialect CREATE INDEX DDL files. It never executes DDL — it writes .sql artifacts for review or for application through your own migration tooling.

# Render index DDL for the default dialects
protean schema render --indexes --domain=my_app.domain

# Restrict to specific dialects
protean schema render --indexes --domain=my_app.domain --dialects=postgresql,sqlite

# Custom output directory
protean schema render --indexes --domain=my_app.domain --output=build

Options

Option Description Default
--indexes Render index DDL (required; nothing is applied without it) false
--domain, -d Path to the domain module (e.g. my_app.domain)
--dialects Comma-separated dialects to render postgresql,sqlite,mssql
--output, -o Root output directory .protean

--indexes requires --domain: rendering partial-index predicates needs the live Index declarations (the Q objects), which an IR file does not carry.

Output structure

One .sql file per element per dialect is written under <output>/schemas/<cluster>/:

.protean/
└── schemas/
    └── Order/
        ├── order.indexes.postgresql.sql
        └── order.indexes.sqlite.sql

Each file is headed with the element FQN and dialect, followed by the CREATE INDEX statements. Dialects that do not support a partial where= or covering include= emit a full index instead. See Indexes for the declaration syntax and dialect support matrix.


Schema format

Generated schemas follow JSON Schema Draft 2020-12 with x-protean-* extension fields for domain metadata. See the Schema Generation guide for the full schema structure reference, including extension fields, nested $defs/$ref resolution, and optional field handling.


Error handling

Condition Behavior
Neither --domain nor --ir provided Aborts with error message
Both --domain and --ir provided Aborts with "mutually exclusive" error
Invalid domain path Aborts with "Error loading Protean domain"
IR file not found or invalid JSON Aborts with descriptive error
Element not found (for show) Lists all available elements and aborts

Domain discovery

The --domain option uses the same domain discovery mechanism as other Protean commands. See Domain Discovery for the full resolution logic.