Custom Values
Custom values allow you to extend entities with organization-specific properties without schema changes. They are the primary extensibility mechanism in CXTMS — use them to store data that doesn't fit the built-in entity fields.
CXTMS provides two complementary systems:
| System | Purpose | Scope |
|---|---|---|
customValues | Runtime key-value dictionary on entities | Per-entity instance — stores actual data |
CustomField | Field metadata definitions | Per-organization — defines field names, types, and UI behavior |
customValues is the storage layer — a flexible Dictionary<string, object?> persisted as JSONB in PostgreSQL.
CustomField is the definition layer — it tells the UI what fields exist, their types, labels, and display rules.
Supported Entities
The following entities include a customValues property:
- Order — customer references, project codes, service levels, incoterms
- Job — consolidation data, vessel info, container types, ETD/ETA
- Commodity — SKUs, lot numbers, serial numbers, hazmat flags
- Contact — DOT numbers, industry codes, account managers, departments
- Charge — rate workflow responses, billing metadata
- OrderCommodity — sequence numbers, handling instructions
- OrderEntity — extended contact details per order role
Working with Custom Values in Workflows
Reading custom values
Access custom values using dot notation in workflow expressions:
- task: Order/Get@1
name: getOrder
inputs:
organizationId: ${organizationId}
orderId: ${orderId}
# Access in subsequent steps:
# ${getOrder.result.customValues.customerPO}
# ${getOrder.result.customValues.projectCode}
Writing custom values
Use entity update tasks to set custom values. Values are merged with existing custom values — you only need to specify the keys you want to add or change.
- task: Order/Update@1
name: updateCustomValues
inputs:
organizationId: ${organizationId}
orderId: ${orderId}
order:
customValues:
customerPO: "PO-2025-ABC"
projectCode: "PROJ-789"
specialHandling: true
requiredDeliveryDate: "2025-02-15"
insuranceValue: 50000
Setting a value to null removes the key from the dictionary.
Creating entities with custom values
Custom values can be set at creation time:
- task: Order/Create@1
name: createOrder
inputs:
organizationId: ${organizationId}
order:
orderNumber: "ORD-2025-001"
customValues:
customerReference: "PO-98765"
specialInstructions: "Temperature controlled"
incoterms: "FOB"
serviceLevel: "Express"
Single value updates
Some entities support updating a single key without reading the entire dictionary:
# Job entity supports ChangeCustomValue for single-key updates
- task: Job/ChangeCustomValue@1
inputs:
organizationId: ${organizationId}
jobId: ${jobId}
key: "masterBL"
value: "MAEU1234567890"
Defining Custom Fields in App Modules
To give custom values structure in the UI, define them as fields in your App Module's entities section. This registers the fields with the platform so they appear in grids, forms, and filters.
entities:
- name: "ParcelShipment"
entityKind: Order
extension: true
displayName:
en-US: "Parcel Shipment"
fields:
- name: "trackingNumber"
displayName:
en-US: "Tracking Number"
fieldType: "text"
isCustomField: true
- name: "originCountry"
displayName:
en-US: "Origin Country"
fieldType: "Country"
isCustomField: true
props:
filterComponent: Countries/Select
allowOrderBy: false
allowFilter: false
Field types
| Field Type | Description | Example Use |
|---|---|---|
text | String data | Names, descriptions, reference numbers |
number | Numeric values | Quantities, measurements, monetary amounts |
date | Date/time values | Ship dates, deadlines, ETAs |
boolean | True/false values | Active flags, hazmat indicators |
list | Options/dropdowns | Status codes, categories |
entityName | Entity references | Links to contacts, locations |
Field props
| Prop | Default | Description |
|---|---|---|
showAs | — | Display component for grid and form rendering |
allowOrderBy | true | Whether the field can be used for sorting |
orderByProperty | — | Alternative property name for sorting |
allowFilter | true | Whether the field can be used for filtering |
filterByProperty | — | Alternative property name for filtering |
filter | — | Filter component definition (component, fieldName) |
isInactive | false | Deactivate the field without removing it |
Displaying Custom Values in DataGrids
Custom values can be displayed as columns in datagrid components using dot notation. Columns support inline editing with automatic persistence.
Basic column with formatting
columns:
- name: customValues.ETA
label:
en-US: ETA
showAs:
component: text
props:
value: "{{ format customValues.ETA L }}"
Inline-editable column
columns:
- name: customValues.ETA
label:
en-US: ETA
enableEdit: true
editor:
component: field
props:
type: datetime
onEdit:
- task: Order/Update@1
inputs:
organizationId: "{{number organizationId }}"
orderId: "{{number orderId }}"
values:
customValues:
ETA: "{{ changedValues }}"
onSuccess:
- notification:
message:
en-US: "ETA has been updated to {{ changedValues }}"
showAs:
component: text
props:
value: "{{ format customValues.ETA L }}"
Custom component editor
columns:
- name: customValues.returnLocation
label:
en-US: Return Location
enableEdit: true
editor:
component: TRTImport/Terminals/Select
onEdit:
- task: Order/Update@1
inputs:
organizationId: "{{number organizationId }}"
orderId: "{{number orderId }}"
values:
customValues:
returnLocation: "{{ changedValues }}"
Filtering Custom Values
Custom values support Lucene-style filtering in GraphQL queries.
Text matching
customValues.serviceLevel: Express
customValues.origin: "Shanghai*"
customValues.projectCode: PROJ-*
Existence check
customValues.insuranceValue: *
Numeric range
customValues.weight: [100 TO 500]
customValues.price: {0 TO *}
Date range
customValues.ETA: [2026-01-01 TO 2026-03-31]
customValues.pickupDate: {* TO 2026-03-23}
Range filters on JSONB fields use PostgreSQL casting for correct comparison semantics (numeric or timestamp), not string comparison.
For full filter syntax, see Filtering.
Sorting by Custom Values
Sort by custom values using dot notation in the orderBy parameter:
query {
orders(organizationId: 1, orderBy: "customValues.priority") {
items {
orderNumber
customValues
}
}
}
Prefix with - for descending order: orderBy: "-customValues.priority"
For full sorting syntax, see Sorting.
Best Practices
- Use custom values for variable, non-critical properties — customer-specific references, project codes, industry-specific fields (DOT numbers, NAICS codes, SKUs, lot numbers)
- Use CustomField definitions for UI structure — register fields in App Module
entitiesso they appear in grids and forms with proper labels and types - Avoid custom values for data requiring complex queries — if you need indexing, joins, or frequent aggregation, consider a dedicated entity field instead
- Use
ChangeCustomValuefor single-key updates where available (Job entity) to avoid reading the entire dictionary - Setting a value to
nullremoves the key — use this to clean up stale properties - Custom values support complex types — arrays (
["SN001", "SN002"]), nested objects, and mixed types are all valid
Related Topics
- Entity System Overview — architecture and entity patterns
- CustomField Entity — field definition schema
- App Module Entities — defining custom fields in YAML
- DataGrid Component — displaying custom values in grids
- Filtering — full Lucene filter syntax including JSONB ranges
- Sorting — sorting by custom value fields
- Workflow Variables — accessing custom values in expressions