Scope Resolvers
What It Is
Scope is the set of named values and helper functions an expression can reference where it runs. Jetstack distinguishes two scopes that matter most for builders:
- automation scope — what an automation action can read while it runs
- canvas scope — what a canvas item can read while it renders
Both scopes feed the same code processor, but each exposes a different set of roots. This chapter is a reference for what those roots are, why scope behaves differently in different places, and how to think about choosing values in builder configuration.
Why It Matters
Scope explains:
- why a token like
iteratorItemresolves in one position of the canvas tree and not in another - why an expression that works in an automation may not work the same way in a canvas
- why some helpers are available everywhere (
today(),concat(...)) while others are scope-specific (trigger(...),iteratorItem) - why a chain like
currentUser.created_by.emailtraverses relations through typed properties and not through arbitrary fields
Without a clear understanding of scope, builder-assisted configuration becomes guesswork.
The Shared Core
Both scopes share the code processor's universal helper catalog: literals, operators (+, -, ==, &&, ??, ? :, …), date helpers (today, formatDate, …), string and collection helpers (concat, length, map, …), casting helpers (toBool, toString, …), crypto helpers, and so on. The full reference is in Code Processor Functions.
What differs between the two scopes is the roots — the named entry points that bring runtime data into the expression.
Automation Scope
Automation scope is centered on execution context. Depending on the running automation and action, it exposes:
| Root / helper | What it brings in |
|---|---|
trigger('name') | A parameter from the trigger that started the automation |
endpoint('name') | A parameter returned by the previous endpoint in the action chain |
var('name') | A local automation variable |
env('name') | A tenant-wide environment variable from app settings |
templateVar('name') | A variable from the surrounding page template (when one exists, e.g. web-triggered automations) |
appParameter('name') | A request/route parameter |
dataQuery(...) | The current data-query helpers (when relevant) |
getSecret('name'), saveSecret(...) | Access to the tenant secret store |
This makes automation expressions a good fit for branching, routing, integration payloads, and scheduling.
Canvas Scope
Canvas scope is centered on interactive UI context. The roots exposed to a canvas item's expressions are:
Tree-position-derived roots
| Root | Resolves to |
|---|---|
iteratorItem | The current iteration item of the nearest iterator-role ancestor |
iteratorIndex | The zero-based position in that iteration |
parentObject | The pinned object of the nearest non-iterator object wrapper |
iteratorItem follows the nearest iterator (GeneralIterator, QueryIterator, TableGeneralIterator, or any item with iterate set). parentObject skips iterators and follows the nearest stable object wrapper. The truth table for typical nestings is documented in Canvas Items And CanvasBuilder — Tree-Position-Derived.
Always-available roots and helpers
| Root / helper | What it brings in |
|---|---|
currentUser | The currently authenticated user resource |
var('name') | A canvas-level variable set by Set variable items or by preload automation |
templateVar('name') | A variable from the surrounding page template |
env('name') | A tenant-wide environment variable from app settings |
appParameter('name') | A request/route parameter |
selection() | The selection app parameter, combined with the current id |
formStatus('formId') | Submission status for a form by its form id |
queryResultCount(queryId) | Row count for a stored Query |
queryResultCalc(queryId, 'propId', 'code') | Calculation result for a stored Query |
getSecret('name') | Access to the tenant secret store |
Property traversal through relations
When a root resolves to a typed object (e.g. currentUser, or iteratorItem inside an iterator with a fixed typeId), expressions can chain through its properties using dot notation: currentUser.email, iteratorItem.created_by.first_name, parentObject.linked_query.parent.id. Each step is resolved through the canvas's property model — relations cross into the related type, primitives terminate the chain.
The canvas builder uses this same model to power its type-aware autocomplete: when it can statically determine the type at the cursor's position, it offers the type's properties as suggestions.
Choosing The Right Kind Of Value
A common canvas design question is whether a parameter should be:
- a literal — when the value is presentational and static
- a context root reference —
parentObject.title,iteratorItem.email,currentUser.id— when the value should follow the surrounding object or iteration - a function call —
appParameter('id'),formStatus('contactForm'),today()— when the value comes from a helper - a composed expression —
concat('Hello, ', currentUser.first_name, '!'),iteratorItem.price * 1.21,currentUser.email ?? 'guest'— when several sources combine
If a single parameter expression starts pulling in too many sources or branches, consider moving the logic upstream: into a Set variable item, into preload automation, or into a model-level calculated property.
Failure Modes
Common scope problems include:
- referencing a root that does not exist at this position — e.g.
iteratorItemin a subtree that has no iterator ancestor - chaining past a primitive — once a chain lands on a string/int field, it is a leaf
- expecting a value from a dynamically-typed root — when an iterator's
typeIdis itself an expression, the autocomplete falls back to the bare root and chained fields are not introspectable - reusing an automation expression inside a canvas verbatim —
trigger(...)andendpoint(...)are automation-only roots - expecting a scalar where the path resolves to an object or array — coerce explicitly with
toString(...),toInt(...), etc., when the consuming parameter is a scalar type
Best Practices
- Keep chains short enough that another implementer can read them at a glance.
- Prefer stable roots:
currentUser,parentObjectinside a wrapper,iteratorIteminside an iterator. - When you find yourself writing the same long chain repeatedly, factor it out into a
Set variableitem near the top of the canvas, or into preload automation. - Use the type-aware autocomplete in the canvas editor to verify that a chain segment actually exists — if the editor doesn't suggest it, the chain probably won't resolve.
- When an expression becomes hard to explain in one sentence, split it into intermediate variables or move the logic into an automation.