CEL Expressions
The expression language behind formula fields, validation rules, visibility, sharing and flow conditions — where ObjectOS uses it, a few examples, and the full language on objectstack.ai.
Full specification: Expressions (CEL) on objectstack.ai. This page is the summary: where ObjectOS uses it, and a few examples.
ObjectOS uses CEL (Common Expression
Language) wherever a definition needs a small, safe expression: it has no side
effects and no I/O, and it is evaluated on the server. An expression sees the
record being evaluated as record (and its previous state as previous), and
— where there is an acting user — that user as current_user.
Where ObjectOS uses it
| Where | What the expression decides |
|---|---|
| A formula field | The field's value, derived from the record |
A field's requiredWhen, visibleWhen, readonlyWhen | Whether the field is required, shown or editable on this record |
| A validation rule | Whether a write is refused (Validation Rules) |
| A sharing rule | Which records a group of users is granted (Record Access) |
An action's visible / disabled | Whether the button is offered |
| A flow's start condition and its branches | Whether a flow runs, and which way it goes (Flows) |
A field's defaultValue | The value a new record starts with |
Examples
Formula field — line-item total:
subtotal: Field.formula({
label: 'Subtotal',
expression: F`record.quantity * record.unit_price`,
}),Validation — close date must be in the future. A script rule's
condition describes the invalid record: when it is true, the write is
refused.
// One validation rule, an entry of the object's `validations`
{
type: 'script',
name: 'close_date_in_future',
message: 'Close date must be in the future',
condition: P`record.close_date <= today()`,
}Visibility — show a field only once the deal is won:
close_reason: Field.textarea({
label: 'Close reason',
visibleWhen: P`record.stage == 'closed_won'`,
}),Flow condition — start a record-change flow only for large amounts:
// The `config` of a `start` node; the rest of the flow is omitted (see Flows).
config: {
objectName: 'opportunity',
triggerType: 'record-after-update',
condition: P`record.amount >= 1000`,
}Permission checks
Since ObjectStack 17.5, current_user.can(object, verb) asks whether the
acting user holds an object permission, answered from that user's effective
permissions:
discount: Field.percent({
label: 'Discount',
defaultValue: cel`current_user.can('crm_quote', 'edit') ? 10 : 0`,
}),The server answers it in a select option's visibleWhen (an option the user
may not pick is refused invalid_option), in formula fields and in a CEL
defaultValue. Where an evaluation carries no permission data — a validation
rule is one — can() is refused rather than guessed, and the expression fails.
When an expression is wrong
It does not fail silently. A malformed expression, or one naming a field the
object does not have, fails os compile with the location and a did-you-mean
hint. At runtime a bad expression throws an attributed error rather than
evaluating to null or false, so the failure shows in logs and the audit
trail instead of quietly corrupting a formula value or a guard decision.
See also
- Formulas — formula fields in an app
- Validation Rules — predicates that refuse a write
- Field Types — the formula field and conditional properties
ObjectQL
The structured query format behind the data API, views, reports and AI tools — where ObjectOS uses it, a few examples, and the full syntax on objectstack.ai.
Field Types
What a field type decides in ObjectOS — the column, the API, the form widget and what the AI Builder asks for — with a few examples and the full catalogue on objectstack.ai.