Skip to content
Talk to our solutions team

Enums

An enum is a named list of allowed values, each carrying optional display metadata, declared once at schema level and referenced from any number of fields.

CapabilityStatus
Declaration, multi-file merge, name resolutionShips
Enum names listed by GET /schemaShips
Values rendered into the served exports (JSON Schema, OpenAPI, Zod, CUE)Ships
Protobuf, Avro and OData renderersImplemented, no route registered — nothing in the service serves them
Field’s enum reference readable from scripts via the getField service functionShips
Write-time membership enforcement from enum:Not wired — add a validations: entry
Read-time enrichment of a value into {value, label, color, icon, group}Implemented, not registered in data.svc
A database enum type (CREATE TYPE … AS ENUM)Never emitted on any backend
A lookup table per enum, with the entity storing a numeric idDoes not exist — the string value is stored in the column
GraphQL enum types in the generated SDLNot generated — enum fields render as String

Enums are a top-level list. They are not declared inside an entity.

KeyTypeRequiredMeaning
enums[].namestringYesThe name a field’s enum: key resolves against. Matching is exact and case-sensitive.
enums[].descriptionstringNoCarried on the enum; not emitted by any renderer.
enums[].values[].valuestringYesThe literal stored in the column and sent over the wire.
enums[].values[].labelstringNoDisplay label. Consumed only by the enrichment hook.
enums[].values[].descriptionstringNoParsed and carried; no consumer.
enums[].values[].colorstringNoDisplay colour. Consumed only by the enrichment hook.
enums[].values[].iconstringNoDisplay icon. Consumed only by the enrichment hook.
enums[].values[].groupstringNoGrouping key. Consumed only by the enrichment hook.
enums[].values[].deprecatedboolNoParsed and carried; no consumer reads it.
enums:
- name: order_status
description: Lifecycle of a sales order.
values:
- value: draft
label: Draft
color: "#9ca3af"
icon: pencil
group: open
- value: confirmed
label: Confirmed
color: "#2563eb"
group: open
- value: shipped
label: Shipped
group: closed
- value: cancelled
label: Cancelled
deprecated: true
KeyTypeEffect
enumstringNames a top-level enum. Resolved by the exporters and by the enrichment hook.
enumvalues[]stringInline value list with no metadata. Never enriched on read — there is no metadata to attach.
entities:
- name: sales_order
primary-key: id
fields:
- name: id
type: ulid
defaultvalue: "ulid()"
- name: status
type: enum
enum: order_status
defaultvalue: draft
validations:
- type: enum
values: [draft, confirmed, shipped, cancelled]
- name: channel
type: enum
enumvalues: [web, pos, partner]

An enum: naming an enum that no file declares is not a load error. The field loads, and the exporters emit a reference to a definition that is not in the document.

The column is a plain string column. For the two fields above, the emitted DDL is:

"status" TEXT NOT NULL DEFAULT 'draft',
"channel" TEXT NOT NULL

Per backend:

BackendColumn type for enum / state
PostgreSQLTEXT
ClickHouseString
DuckDBVARCHAR(255)
SQLiteTEXT

The deployable service wires PostgreSQL for tenant datastores. The other three dialects exist in the engine but cannot be selected from tenant configuration — no pool factory is registered for ClickHouse, and DuckDB and SQLite are rejected by pool-config validation.

Membership is enforced by a field validation, not by the enum reference. Three validators cover it:

validations[].typeBehaviour
enumFails when the value is not in values.
inIdentical to enum.
notinFails when the value is in values.
- name: status
type: enum
enum: order_status
validations:
- type: enum
values: [draft, confirmed, shipped, cancelled]
message: "status must be a known order status"
code: ORDER_STATUS_INVALID

Rules that apply to all three:

  • They run on create and on update.
  • They are skipped when the payload does not carry the field, so a partial update that omits the column is never checked.
  • Comparison is equality with a stringified fallback, so the number 1 matches the value "1".
  • Omitting values: makes the validator pass silently. It is not a load error.
  • The values: list is independent of the enum’s values. Nothing checks that the two agree — keeping them in step is your job.
  • On failure the error carries rule enum and code ENUM (or IN / NOTIN), overridable per rule with code: and message:. It surfaces through the REST create/update failure envelope; see the HTTP reference.
  • An unrecognised validations[].type fails loud at write time with VALIDATION_UNKNOWN — a typo does not silently disable the check.

The schema-validation code INVALID_ENUM_VALUE exists in the error catalogue but has no emitter; you will not see it.

Value metadata: label, colour, icon, group

Section titled “Value metadata: label, colour, icon, group”

The enrichment hook replaces an enum field’s raw string with a structured value on read:

{
"status": {
"value": "draft",
"label": "Draft",
"color": "#9ca3af",
"icon": "pencil",
"group": "open"
}
}

color, icon and group are omitted when empty; description and deprecated are never emitted.

This hook is not registered in the deployable service. The service builds its own hook chain and the engine’s baseline chain registers only defaults, validate and audit, so reads return the raw string. Labels, colours, icons and groups are declared-but-inert unless a host registers the hook itself. Treat them as documentation of intent, or resolve them client-side from an export.

Enum names are canonicalised to PascalCase wherever a named type is emitted: order_status becomes OrderStatus.

ExportNamed enum renders as
GET /schema/jsonschema.json$defs.OrderStatus = {"type":"string","enum":[…]}; the field emits {"$ref":"#/$defs/OrderStatus"}
GET /schema/openapi.jsoncomponents.schemas.OrderStatus; the field emits a $ref
GET /schema/zod.tsexport const OrderStatusEnum = z.enum([…]) plus an inferred type
GET /schema/cue#OrderStatus: "draft" | "shipped"
GET /schema/graphqlString — no GraphQL enum type is generated
Protobuf (no route)enum OrderStatus with an ORDER_STATUS_UNSPECIFIED = 0 member prepended and values upper-snake-cased
Avro (no route)An enum record whose symbols are the values with every character outside [A-Za-z0-9_] replaced by _
OData (no route)<EnumType Name="OrderStatus"> with ordinal Value attributes

The Protobuf, Avro and OData renderers are complete, but no endpoint registers them and nothing else in the service calls them — there is no way to fetch a .proto, .avsc or OData $metadata document. Only the four routed exports above are reachable.

No renderer carries label, color, icon, group, description or deprecated. Exports contain values only.

GET /schema returns the enum names for the tenant as a flat list. The per-entity detail response does not report which enum a field references; use the exports for that.

Enums merge by name across every YAML file under the loaded root, last write wins — a later file declaring order_status replaces the earlier one wholesale, with no diagnostic. This is the opposite of entities and traits, which keep the first definition and log the duplicate. There is no deep merge: you cannot add a value to an enum by re-declaring it with one entry.