Portal Community

Structure

public sealed class ExpressionPolicy
{
    public EvaluationStage EvaluationStage { get; init; } = EvaluationStage.AtConfigLoad;
    public EvaluatorKind   EvaluatorKind   { get; init; } = EvaluatorKind.Template;
}

EvaluationStage

Determines the point in the execution lifecycle at which the field's value is resolved.

AtConfigLoad

Evaluated once when the workflow instance loads or the node's configuration is initialised. The resolved value is cached and reused across all executions.

Use when: The value is fixed in the workflow definition and does not depend on runtime data.

Example fields
SMTP host / port — infrastructure config
Approval strategy — "AnyOne", "NofM", "Unanimous"
HTTP method — "GET", "POST"
Static labels or identifiers

AtInputReady

Evaluated just before the node executes, after all upstream data has been resolved and mapped into the node's input. Has full access to workflow variables, upstream outputs, and live data.

Use when: The value depends on data from previous nodes or workflow runtime state.

Example fields
Email recipient — {{workflow.customer.email}}
Slack channel — determined by workflow context
Form assignee — determined by a preceding step
HTTP request body — built from upstream data

NodeControlled

The executor itself determines when to evaluate the field. The expression engine does not automatically trigger evaluation.

Use when: Advanced nodes with custom evaluation timing that does not fit the standard two-stage model.

AsLiteral

The value is treated as a raw constant. No expression processing occurs — the value is used exactly as stored in config. Use when a value looks like a template expression but must not be processed.

EvaluatorKind

Determines the expression language used to evaluate the field value.

Template

Evaluates handlebars-style {{expression}} placeholders. The most common evaluator.

"Hello {{workflow.customer.firstName}}"
"{{inputs.userId}}"
"{{env.API_BASE_URL}}/users/{{payload.id}}"

Supports: workflow variable references, upstream output references, environment variables, simple dot-notation paths.

JavaScript

Evaluates a JavaScript snippet. Provides full scripting capability for complex transformations.

JSON.stringify({
  userId: inputs.customerId,
  amount: inputs.orderTotal * 1.1,
  currency: workflow.tenant.defaultCurrency || 'USD'
})

Use for: conditional logic, data transformation, arithmetic, combining multiple upstream values.

JsonPath

Extracts a value from a JSON document using JSONPath syntax.

$.customer.address.city
$.items[0].productId
$.results[?(@.status == 'active')].id

Use when the field value should be extracted from a larger JSON payload.

Literal

The value is used as-is. No expression engine is invoked. Use for fixed constants or when the value superficially resembles a template but must not be evaluated.

None

The field value is not evaluated from config at all. The executor sets it at runtime (e.g., an output field populated after the node completes its operation).

Use for: output fields populated by the executor, runtime-generated identifiers (message IDs, timestamps), values from external system responses.

Stage × Kind Quick Reference

EvaluationStageCommon EvaluatorKindsNotes
AtConfigLoadTemplate, LiteralConfig is static; JavaScript rarely needed at load time
AtInputReadyTemplate, JavaScript, JsonPathFull runtime data available
NodeControlledAnyNode decides
AsLiteralOverrides kindStage takes precedence; kind ignored
Output fields (any stage)NoneOutput fields are never evaluated from config

Decision Guide

Is the value fixed in the workflow definition?
  YES → AtConfigLoad
  NO  → AtInputReady

Does it use {{placeholders}}?
  YES → Template
  NO, needs logic/transformation → JavaScript
  NO, extracts from JSON path → JsonPath
  NO, is a constant → Literal
  NO, set by the executor after running → None
Output field convention For output fields that the executor populates after running, use EvaluationStage.AtInputReady + EvaluatorKind.None. The AtInputReady stage is a convention signalling "this is a runtime field" even though no evaluation occurs.