Skip to content
Last updated

Fields (columns) are the schema of an Object or Table. Every field has a type and an optional per-type metadata object, plus the constraints and defaults described at the bottom of this page.

Create a field with:

frontline object field create <object> --data '{"name":"<label>","type":"<type>","metadata":{ ... }}'
# Tables use the same shape:
frontline table field create <table> --data '{"name":"<label>","type":"<type>","metadata":{ ... }}'

Or via the Public API: POST /public/v1/objects/{name}/fields.

The create/update body is strict — unknown top-level keys return a 400.

Data types & metadata

Typemetadata keysExample
stringformat: text | email | url | phone_number; extendedField (bool){"format":"text","extendedField":true}
numberformat: integer | decimal | percent | currency; decimals; currency{"format":"currency","currency":"USD","decimals":2}
boolean(none){}
datetimezone (IANA); format (Luxon display pattern); timeFormat (12h | 24h){"timezone":"America/New_York","format":"MM/dd/yyyy","timeFormat":"12h"}
dateOnlyformat{}
select (tags)mode: singleSelect | multiSelect{"mode":"singleSelect"}
relationmode: single | multi; relatedTableId; displayColumn{"mode":"multi","relatedTableId":123,"displayColumn":45}
prismaRelationprismaModel: User | Conversation; displayField; mode: single|multi{"prismaModel":"User","displayField":"fullName","mode":"multi"}
fileshowPreview (bool); allowedFileTypes (string[]); maxFileSize (bytes){"showPreview":true}
avatar(none){}
formulaexpression (object, required); applyIf (object, optional); numberConfig, dateConfig, stringConfig (objects, optional){"expression":{"type":"constant","value":42}}

select maps internally to a tags field, but the API still returns "type":"select". Internal-only types (autoIncrement, kanbanViewOrder) and the composedField string format are reserved for the platform and rejected by the API.

Metadata validation. When you include a metadata object, it is validated with the same rules as the in-app field editor. Unknown keys are rejected with suggestions (for example time_format → use timeFormat, timeZone → use timezone). If you provide metadata, the type's key fields are required: string/number need format, date needs timezone (which must be a valid IANA timezone name from the allowed list, e.g., UTC, America/New_York, America/Chicago, etc.), select needs mode, relation needs relatedTableId + displayColumn + mode, prismaRelation needs prismaModel + displayField + mode, and formula needs expression. To accept defaults, omit metadata rather than sending {} (an empty object fails for types that require a key).

Date format values. For type: "date", metadata.format must be a Luxon display pattern accepted by the UI Date Format dropdown — not legacy column-kind values like datetime, date, or time. Allowed: MM/dd/yyyy, dd/MM/yyyy, yyyy-MM-dd, MMM d, yyyy, d MMM yyyy. Optional timeFormat: 12h or 24h. Field list/get responses include a metadata object (in addition to promoted top-level keys like timezone and time_format) so CLI round-trips work.

Text: normal vs long

Both use "format":"text". The extendedField flag controls how it renders:

ValueUIUse for
{"format":"text"}Single-line inputNames, short labels
{"format":"text","extendedField":true}Multi-line areaDescriptions, notes, summaries
# Long-text Description field
frontline object field create tickets --data '{
  "name": "Description",
  "type": "string",
  "metadata": { "format": "text", "extendedField": true }
}'

On read, a long-text field surfaces "extended_field": true in the field output.

Select options

select (single- or multi-select) options cannot be created inline — the create call only sets mode. Create the field first, then add each option:

frontline object field create deals --data '{"name":"Priority","type":"select","metadata":{"mode":"singleSelect"}}'
frontline object option create deals <field-id> --data '{"name":"High","color":"Magenta"}'

Passing metadata.options, metadata.tags, or a top-level options/tags array on create is rejected (400). On update, replace options via the top-level tags array.

relation vs prismaRelation

  • relation links a record to records in another Object (e.g. a Deal → a Company). Requires relatedTableId (the target object's numeric id) and displayColumn (the field id to show as the label).
  • prismaRelation links a record to a platform entity, most commonly an account User (assignee/owner). Requires prismaModel ("User" or "Conversation") and displayField (e.g. "fullName"). The built-in Users field on People, Deals, and Tickets is a prismaRelation.
# Assignee field that points to platform users
frontline object field create deals --data '{
  "name": "Owner",
  "type": "prismaRelation",
  "metadata": { "prismaModel": "User", "displayField": "fullName", "mode": "single" }
}'

# Assign users on a record — array of numeric user IDs
frontline object record update deals <record-id> --data '{ "Owner": [42, 57] }'

On read, a prismaRelation field surfaces prisma_model, display_field, and relation_mode.

Formulas: dynamic calculated fields

Formula fields enable spreadsheet-like calculated values for both standard CRM objects and custom tables. They automatically recalculate when dependent fields, relations, or back-relations are modified.

A formula field metadata requires an expression object (the AST representing the calculation) and an optional applyIf QueryDSL filter (the condition under which the formula is executed).

{
    "name": "Total Cost",
    "type": "formula",
    "metadata": {
        "expression": {
            "type": "operator",
            "operator": "multiply",
            "arguments": [
                { "type": "field", "field": "[Quantity]", "fallbackValue": 0 },
                { "type": "field", "field": "[Unit Price]", "fallbackValue": 0 }
            ]
        },
        "applyIf": {
            "path": "[Status]",
            "operator": "equals",
            "value": "Active"
        }
    }
}

AST Node Types

Formula expressions are built recursively using the following node types:

  1. constant: A static literal value.
    • value (string or number)
  2. field: References a local field ("[Field Name]") or direct relation field ("[Relation Name].[Field Name]").
    • field (string)
    • fallbackValue (optional, string or number)
    • Percent scaling: When referencing a standard number column with "format": "percent", its value (or fallbackValue) is automatically divided by 100 during evaluation so that a whole number like 10 behaves mathematically as 0.1.
  3. operator: Performs mathematical or string operations.
    • operator: "add", "subtract", "multiply", "divide", or "concat"
    • arguments: Array of formula nodes
  4. aggregate: Aggregates records across relations or back-relations.
    • operation: "count", "sum", "avg", "min", "max", or "sumProduct"
    • field (required field to aggregate in the target table)
    • relation (required for direct relations; optional for back-relations)
    • isBackRelation (optional, boolean)
    • backRelationColumnId (optional, number, the target table's relation column pointing back)
    • arguments (optional array of formula weight nodes for "sumProduct")
    • filter (optional QueryDSL filter to scope aggregated records)
  5. padLeft: Pads a string calculation to a specific length.
    • value (formula node returning base value)
    • length (number)
    • char (single character string)
  6. ifElse: Evaluates condition branches inside the expression.
  7. timeOperator: Performs date/time addition, subtraction, or difference operations.
    • operator: "add", "subtract", or "diff"
    • arguments: Array containing exactly two formula nodes
    • unit: "second", "minute", "hour", "day", "month", or "year"

For details on the QueryDSL structure and supported operators by field type, see the Querying and Filtering guide.

Constraints and Limitations

  • Nesting Depth: A formula AST cannot exceed a maximum depth of 5 (root-to-leaf node count; the root node is depth 1; field and constant leaves are depth 1). Depth counts arguments, then/else, and padLeft.value sub-trees; QueryDSL filters in applyIf, ifElse.filter, or aggregate.filter do not count.
  • Flat Model Constraint: A formula column cannot reference another formula column (no formula chaining).
  • Standalone Relations: A relation column cannot be referenced as a standalone field in a formula.
  • Strict Typing: Mathematical operators (add, subtract, multiply, divide) and mathematical aggregations (sum, avg, sumProduct) only accept numeric inputs.
  • Read-Only: Formula fields are read-only (readOnly: true). You cannot manually write or update a formula column's value through the record update API.

String output formatting. When the inferred output type is string, optional stringConfig controls display: format may be text, email, url, or phone_number. Set extendedField: true together with format: "text" for long (multi-line) text, matching standard string columns.

Previewing Formula Evaluation

You can preview the output of a formula on existing data before creating the field:

  • Objects: POST /public/v1/objects/{name}/fields/preview-formula
  • Tables: POST /public/v1/tables/{name}/fields/preview-formula

Constraints

Set on create or update:

KeyMeaningExample
requiredField must have a value on every record"required": true
uniqueValue must be unique across all records"unique": true
frontline object field update <object> <field-id> --data '{"required": true, "unique": true}'

Defaults

Pass defaultValue to backfill new records (and existing rows on creation):

frontline object field create deals --data '{"name":"Priority Score","type":"number","metadata":{"format":"integer"},"defaultValue":0}'
  • For select fields, defaultValue is the option name.
  • Date fields accept the dynamic placeholders NOW and TODAY, which resolve at record-creation time rather than being frozen at field-creation time.
  • relation, prismaRelation, file, and avatar fields cannot have a default value.

Record types (Objects only)

By default a new field is added to all record types of the object. Pass record_type_id to scope it to a single record type. See Record Types.

See also