Skip to main content

Fields and field options

Fields define what data an app stores and how that data appears in the UI. Every app exports an AppField[] array from fields/index.ts. The engine reads this array at startup and builds the schema, form controls, and validation rules from it.

This page covers data types, the type system, field options, calculated fields, and naming conventions.

Data types

Each field has a type property drawn from one of three unions defined in api/schema/typings/schema-field.ts.

DataType - the primary data type:

text · lookup · lookupMulti · appsLookup · linkto · linkslist · fileslist · peoplelist · date · datetime · person · bool · number · object

TextType - sub-type used when type is 'text':

string · keyword · text · richtext

NumberType - sub-type used when type is 'number':

unknown · float · integer

CalcType - for computed fields (see Calculated fields below):

calcfield · rollup · datarollup · treerollup · shadow · tablecalcfield

A field that stores a single-line string uses type: 'text' with a text sub-type of 'string'. A field that stores a currency amount uses type: 'number' with a number sub-type of 'float' and a decimal_places option.

Type system

The engine generates TypeScript types from field definitions so that record access is fully typed:

const { entity, entityOld, records } = makeEntity(fields, actions);
// entity.title, entity.state - fully typed based on field definitions

Key type utilities:

  • FieldName<Entity> - all accessible field names
  • EditableFieldName<Entity> - writable fields only
  • fieldName__resolved - expands to { caption, position } for lookup fields
  • fieldName__list - expands to Array<ListEntry> for list-type fields

Use these utilities in actions and view logic to keep field references type-safe. The compiler will catch misspelled or removed field names at build time.

Field options

The AppField.options object controls rendering, validation, and behavior. There are 50+ available options. The table below lists the most commonly used ones.

Form controls and rendering

OptionTypePurpose
custom_form_controlstringOverride the default form widget: 'search-box', 'drop-down-simple', 'color', 'link-list', etc.
gridview_rendererstringCustom list/grid cell renderer: 'circle_percent', 'indicator', 'rich_text_line', etc.
plain_rendererstringCustom plain-view renderer: 'colorful-lookup', 'avatar-image', 'work-progress-bar', etc.
code_editor_enabledbooleanShow a code editor instead of a text input
code_editor_languagestringLanguage for syntax highlighting: 'javascript', 'json', 'html', etc.

Validation and input

OptionTypePurpose
restrict_inputstringInput validation pattern: 'email', 'percent', 'url', 'phone', 'int'
input_maskstring/objectInput mask (e.g. phone format)
max_lengthnumberMaximum character count
decimal_placesnumberDecimal precision for number fields
number_min_value / number_max_valuenumberNumeric range validation

Defaults and help text

OptionTypePurpose
default_value_expressionstring/bool/numberDefault value applied to new records
help_textLanguageTextObjectTooltip/help text shown on the field
placeholder_textLanguageTextObjectPlaceholder text in the input

Lookup display

OptionTypePurpose
lookup_entries_formattingobjectPer-lookup-entry colors, icons, and text colors
lookup_entries_localizationobjectPer-lookup-entry translations

Access and lifecycle

OptionTypePurpose
accessstringField access level: 'workspaceAdmin', 'workspaceTeam', 'groups'
changeset_hidebooleanHide field changes from the change history
clear_on_transitionbooleanClear the value when an action fires
conditional_formattingstringDynamic formatting function name

Options are additive. A field with no options uses the engine's default widget and validation for its data type. Add options only when you need to override that default.

Display formatting

OptionTypePurpose
formatting_preLanguageTextObjectPrefix displayed before the value (e.g., "$")
formatting_postLanguageTextObjectSuffix displayed after the value (e.g., "h", "kg")
special_decimal_formatstringSpecial numeric formatting: 'HH:MM' renders decimals as hours:minutes

Schema type markers

When the API returns a schema (via /api/schema/{WS}!{APP}), each field includes an ed_custom_field_type property that identifies how the field behaves in the system:

Schema typeMeaningExample fields
authorinfoPerson field (stores user GUID)keeper_id, created_by_account_id
lookup_customLookup with custom valuesstate, priority
lookup_link_to_entityLink to another recordparent_id, c_related_task
linklistMulti-link fieldrecord_links
peoplelistMulti-person fieldassignees_list
file / filelistFile attachment fieldattachments
richtextRich text (Lexical editor)description

These markers determine how the API resolves values during read and write operations. For example, authorinfo fields accept both user GUIDs and full names - the API resolves names to GUIDs automatically.

Multi-language support

Field captions and several text options support multiple languages through the LanguageTextObject type. Supported language codes are defined by CaptionLanguage:

type CaptionLanguage = 'en' | 'uk' | 'ru' | 'zh' | 'de' | 'fr' | 'es';

Use a language map anywhere the engine expects translatable text:

caption: { en: 'Priority', uk: 'Пріоритет' }

The following field properties accept LanguageTextObject values: caption, help_text, placeholder_text, formatting_pre, formatting_post, and default value expressions.

Calculated fields

Calculated fields derive their values from other fields or from related records. They use one of the CalcType values instead of a DataType.

Calc typeBehaviorExecution
calcfieldSimple formula over the current record's fieldsSynchronous
rollupAggregate value from child recordsAsynchronous (Processor)
datarollupData-level rollupAsynchronous (Processor)
treerollupAggregate across a tree hierarchyAsynchronous (Processor)
shadowDenormalized copy of a field from a linked recordAsynchronous (Processor)
tablecalcfieldEditable grid calculationAsynchronous (Processor)

Simple calcfield formulas execute synchronously when the record loads. All other calc types are asynchronous - the background Processor evaluates them after the triggering change is saved.

Calc field definitions live in fields/calc-fields/index.ts. The build system bundles this directory separately so the formulas can run in the browser without pulling in server-only code. See Package structure for where this fits in the directory layout.

Field naming conventions

Custom fields use the c_ prefix - for example c_priority, c_due_date, c_total_cost. This prefix distinguishes app-specific fields from system fields.

System fields are provided by @comind/base and have no prefix: title, description, state, creation_date, update_date, keeper_id, and so on. Every app inherits these automatically.

When referencing fields in actions, view logic, or form layouts, always use the db name (c_priority, not the caption). The TypeScript type system will enforce correct names at compile time.