Expressions

What It Is

Jetstack uses expressions to make configuration fields dynamic. Expressions are evaluated through the active-resource expression pipeline, not by simple text substitution. That pipeline can resolve variables, run code processor functions, translate table-column references, and use utility helpers.

Why It Matters

Expressions are one of the most important cross-cutting mechanisms in the platform. They appear in:

  • property visibility and editability rules
  • property default and initial values
  • property calculations and masks
  • property value switching logic
  • query filter parameters
  • custom query parameter defaults
  • view action visibility rules
  • canvas item configuration
  • automation parameters and branching logic

Because expressions appear in so many places, inconsistent expression design leads directly to confusing implementations.

Supported Expression Parts

Jetstack registers these dynamic expression syntaxes:

SyntaxMeaningTypical use
{$...}dot-walker variable or property resolutionobject values, nested relations, current context fields
{{ ... }}code processor expression, stringifiedtemplate interpolation, email bodies, layout placeholders, anywhere a string result is embedded
{=...}code processor expression, raw valuecomparisons, boolean logic, function calls, calculations — anywhere a typed result is needed
{%...%}table-column resolutionquery and SQL-aware dynamic configuration
{?...}utility helper resolutionhelper-level expression handling

{{...}} and {=...} evaluate identically under the hood (both use the Code Processor); the difference is only in the return-shape post-processing. See Expression Parsing And Shortcodes for the details and trade-offs.

These formats can appear in one field or be combined, depending on the target configuration surface.

Evaluation Model

Jetstack evaluates expressions by repeatedly resolving the smallest supported dynamic segments until no dynamic segments remain.

flowchart TD
    A[Configured field value] --> B[evalExpression]
    B --> C[Create context stack or merged context]
    C --> D[Resolve variable segments]
    C --> E[Resolve code or math segments]
    C --> F[Resolve table-column segments]
    C --> G[Resolve utility segments]
    D --> H[Replace resolved segment]
    E --> H
    F --> H
    G --> H
    H --> I{Any dynamic parts left?}
    I -- Yes --> C
    I -- No --> J[Final scalar or typed value]

This matters because a field can resolve in several stages:

  • first read object values
  • then build a boolean expression
  • then evaluate that boolean expression

That is exactly how many property condition fields behave.

Context Stack

Expressions are evaluated against context. The caller can evaluate an expression:

  • only against the current object
  • against the current object plus an additional context stack
  • against a merged stack that hides the default object

Depending on where an expression runs, the context may include:

  • the current property
  • the parent object
  • the current active resource
  • the current automation
  • the current canvas
  • app parameters
  • focus template variables
  • secrets provider access through code processor functions

This is why the same expression string can behave differently in different platform areas.

Common Expression-Driven Fields

Property Conditions

  • show_conditions
  • add_conditions
  • edit_conditions

These fields usually resolve to booleans after variable expansion and code evaluation. They decide whether a property is visible, addable, or editable in the current form context.

Property Defaulting And Calculation

  • default_value
  • form_initial_value
  • calculation
  • mask
  • value_switch

These fields can alter form behavior, display behavior, or resulting values.

Query Inputs

  • advanced filter parameters
  • custom query parameter defaults
  • subquery-aware filter parameters

These often evaluate before a query is run and may need strict resolution.

View Actions

  • action showCondition
  • confirmation text that supports code processor expressions

Canvas Configuration

Canvas item parameters are authored as code-processor expressions. Each value is evaluated against the canvas scope at render time, with currentUser, iteratorItem, parentObject, canvas variables, and the standard helper catalog in scope. Pickers (resource selectors, select dropdowns, checkboxes) write their values as the equivalent literal expression.

Rich-text Editor-mode fields (such as the P item in Editor mode) embed the same expression evaluation through {=...}, {{...}}, and {$...} shortcodes inside the HTML content. See Canvas Items And CanvasBuilder for details.

Automation Configuration

Automation actions can use trigger values, previous endpoint parameters, local variables, app parameters, query helpers, and secrets through expressions.

How To Use Expressions Well

Prefer Business Meaning Over Cleverness

Bad expression design usually looks like one of these:

  • several unrelated conditions packed into one unreadable line
  • hidden dependence on a field that implementers will not recognize
  • using expressions where a query, role, or field design decision would be clearer

Good expression design usually looks like:

  • a short direct condition
  • a clear defaulting rule
  • one obvious relation to the surrounding feature

Choose The Right Syntax

  • use {$...} when dot-walker access to context values is enough
  • use {{ ... }} when you need a code-processor expression that renders into a string (email bodies, template content, layout placeholders)
  • use {=...} when you need a code-processor expression to return a raw typed value (boolean conditions, math, filter parameters)
  • use {%...%} only when a feature explicitly needs table-column semantics

Be Aware Of Return Shape

Some callers expect:

  • plain strings
  • booleans
  • arrays
  • math-preserving values
  • non-string immediate return values

That is why an expression that works in one place may need adjustment in another.

Examples

Conditional Display

{=toBool({$this.is_active.raw()}) && {$this.customer_type} == "enterprise"}

Use this when a field should appear only for active enterprise customers.

Initial Form Value

{$this.owner.full_name}

Use this when the form should begin with a value derived from related context.

Date-Driven Default

{=date_format(date_add(date_now(), "P14D"), "Y-m-d")}

Use this when the default should be two weeks from now.

Failure Modes To Watch

  • invalid scope path
  • assuming a value is already typed when it is still a string
  • referencing fields that are not available in the current context
  • overloading one field with too much logic
  • mixing data-model responsibilities with UI-only conditions

Best Practices

  • Prefer simple expressions that explain business intent.
  • Keep show_conditions, add_conditions, and edit_conditions close to the property they control.
  • Use shared references rather than inventing undocumented syntax conventions.
  • Validate context assumptions in canvases and automations because their scopes are broader and more specialized than standard object forms.
  • When an expression becomes hard to explain in one sentence, consider moving the logic into a query, permission rule, or automation variable.