Skip to main content

Property types (YAML)

A property type is a schema — it defines the shape of a class of data. Its list of schemaNodes are the fields; each property of that type fills those fields in. If a property type is a table definition, a property is a row. This page is the deep reference for the type side and the cotctl property-types command; for the type-vs-instance mental model and the property side, start with Properties & types.

Two separate commands. cotctl property-types manages type definitions (this page). cotctl properties manages the instances. They're distinct top-level commands, applied in that order.

The shape of a property type

kind: PropertyType
code: location # upsert key, immutable
display: Location
hidden: true
schemaNodes:
- key: address
display: Address
basicType: string
validators:
required: true
- key: city
display: City
basicType: string
isIndexable: true
FieldRequiredNotes
kindYesAlways PropertyType
codeYesUnique per company. Immutable after creation
displayYesUI display name
hiddenNoDefaults to true. See visibility below
viewPermissionsConditionalAccessRole names. Required (non-empty) when hidden: false
schemaNodesNoThe field definitions (keys must be unique)
isActiveNoDefaults to true
displayTranslations, propertyImportPermissions, hierarchyLevelNoLocalised label, import roles, hierarchy depth

Schema nodes: the fields

Each entry in schemaNodes defines one field. The key ones:

schemaNodes:
- key: office # the field name — becomes a schemaInstance key
display: Office Location
basicType: COTProperty # the datatype
subType: office_location # required for COTProperty — the target type's code
isArray: false
validators:
required: false
weight: 10 # display order (lower first)
isActive: true
Node fieldRequiredNotes
keyYesUnique within the type. The key that appears in a property's schemaInstance
basicTypeYesThe datatype (see the catalog below). Immutable once the node exists
subTypeConditionalThe target PropertyType code, required by the backend for COTProperty. Immutable
isArrayNoDefaults to false. Makes the field a list. Immutable
display, descriptionNoLabels
validatorsNorequired, min/max, arrayMin/arrayMax, and a custom validator list
default, weight, visualizationNoDefault value, display order, rendering hint
isActive, isHidden, isNonEditable, isIndexableNoNode-level flags

The basicType catalog

There are exactly eight types:

basicTypeHoldsNotes
stringFree text, URLs, codesThe workhorse; indexable, arrayable
numberInteger or floatmin/max validators apply
dateISO 8601 datetime
booleantrue/false
linkA URL
fileA file _id
COTPropertyA property _idNeeds subType (the target type's code); the picker is filtered to it
COTUserA user _idThe picker lists users

How schema nodes connect to properties. A property of this type carries a schemaInstance — a key/value map whose keys are exactly the key fields you define here. Define a node key: city, and every property of the type may set schemaInstance.city. To see the valid keys for a type, run cotctl property-types get <code>.

Immutability and the non-destructive merge

A node's basicType, subType, and isArray are frozen once the node exists. Everything else on a node (display, validators, isActive, weight, …) is editable, but you cannot change what a field is after data may already conform to it. If your YAML changes one of the three frozen attributes on an existing key, cotctl refuses the whole document with an immutability error — before touching the backend. To reshape a field, retire the old node and add a new one under a different key.

Omitting a node never deletes it. When you apply a type, any node that exists on the server but isn't in your YAML is preserved — merged back into the update. So a partial YAML can't accidentally drop fields. To retire a node, include it explicitly with isActive: false; there's no way to permanently delete a schema node through YAML.

Visible vs. hidden types

Most property types are internal machinery and stay hidden: true. Set hidden: false only for catalogs users actually browse in the UI (locations, teams). When you do, you must list the roles allowed to see it:

hidden: false
viewPermissions:
- Admin
- "Human Resources" # role names can contain spaces — quote them

viewPermissions are AccessRole names, case-sensitive. This is enforced before any API call — hidden: false with an empty viewPermissions fails validation. Conversely, flipping a visible type back to hidden: true clears its viewPermissions, and cotctl warns you when an apply would do that.

Working with property types

# Read
cotctl property-types list # active (default)
cotctl property-types list --all # include inactive
cotctl property-types list --search loca # min 3 chars
cotctl property-types get location
cotctl property-types export location -o location.yaml
cotctl property-types export -o all-types.yaml # every type, multi-doc

# Write
cotctl property-types apply -f location.yaml --dry-run
cotctl property-types apply -f location.yaml -y

# Retire
cotctl property-types deactivate location

apply takes -f/--file (required), --dry-run, and -y/--yes, and handles multi-document files. There's no delete — deactivate (setting isActive: false) is the removal path.

A COTProperty node's subType isn't checked at apply time. If a node points at a property type that doesn't exist yet, cotctl accepts it and it fails at runtime. Apply the referenced type first — in a directory apply, order your files so dependencies come first.

Apply order

Property types are applied second, after roles (because viewPermissions references role names) and before properties, workflows, and job titles that reference them. cotctl apply --dir enforces the order.

See also

  • Properties & types — the type-vs-instance model and the property (instance) side
  • Roles — the viewPermissions a visible type references
  • Job titles — reference property types via allowedExtensions
  • apply — property types are applied before properties