Skip to content

Variables and step outputs

Use these bindings anywhere QuickFlo accepts a Liquid template. Autocomplete shows the values available at the current step.

Step outputs are referenced by their step ID directly — not nested under a steps prefix:

{{ my-step-id.someOutputField }}

For example, if you have a step with ID fetch-users that returns a list of users:

{{ fetch-users.data }}
{{ fetch-users.data[0].name }}
{{ fetch-users.totalCount }}

Every step exposes a $meta object with execution metadata:

{{ fetch-users.$meta.success }} // boolean — true if the step ran without throwing AND wasn't an error-severity operational failure
{{ fetch-users.$meta.skipped }} // boolean — true if the step's skipCondition matched
{{ fetch-users.$meta.durationMilliseconds }} // number — execution time in ms
{{ fetch-users.$meta.stepType }} // string — step type name
{{ fetch-users.$meta.operationalStatus }} // 'ok' | 'warning' | 'error' (see Operational Errors)
{{ fetch-users.$meta.error }} // object — present when the step *threw* (execution error)
{{ fetch-users.$meta.operationalErrors }} // array — present when classifyOutput() flagged the result (operational error)

$meta.error vs $meta.operationalErrors vs $errors — three different surfaces, three different jobs:

  • $meta.error (per-step, singular object) — only set when the step’s code threw. Use step.$meta.error.message to read the thrown message.
  • $meta.operationalErrors (per-step, array) — only set when the step ran successfully but the result was a failure (HTTP 4xx, SMTP rejection, file not found, LLM rate limit). The original output is still readable. Use step.$meta.operationalErrors[0].code and .message.
  • $errors (workflow-global, array) — every error from every step in the run, aggregated. Use it to ask “did anything fail anywhere?” — see Operational Errors below.

For “did this specific step succeed?” use step.$meta.success. It is false for both execution and operational failures. See Warnings and partial results for the practical pattern.

$meta.error is an object, not a string. When present, it has these fields:

FieldDescription
.messageHuman-readable error message
.nameError class name (e.g., WorkflowError, Five9Error)
.codeOptional machine-readable code (e.g., HTTP_CLIENT_ERROR)
.severityOptional severity level
.isRetryableOptional boolean—true when QuickFlo considers the error temporary
{{ fetch-users.$meta.error.message }}
{{ fetch-users.$meta.error.code }}

For operational errors specifically, use $meta.operationalErrors (an array) or the global $errors variable described below.

These global variables are available in every template expression:

VariableDescription
{{ initial.* }}Data passed when the workflow execution started
{{ step-id.* }}Output from a completed step, referenced by its step ID
{{ $env.* }}Environment variables
{{ $connections.* }}Connection credential objects
{{ $vars.* }}Workflow variables set by set-variable steps
{{ $util.* }}Utility generators (UUIDs, timestamps, etc.)
{{ $execution.* }}Current execution identity — see Execution Context below
{{ $errors.* }}Array of operational and execution errors that have accumulated during the run — see Operational Errors below

The initial object contains the data that triggered the workflow execution. Its structure depends on the trigger type. To define the shape your workflow expects and its defaults, see Initial Data.

When a workflow is triggered via webhook, the request body fields are spread to the root of initial, and a webhook context object provides access to the full request:

{{ initial.someFieldFromBody }}
{{ initial.webhook.query.page }}
{{ initial.webhook.query.filter }}
{{ initial.webhook.headers['content-type'] }}
{{ initial.webhook.body }}
{{ initial.webhook.params }}

The webhook object contains:

FieldDescription
webhook.bodyRaw request body
webhook.queryURL query parameters (?key=value)
webhook.paramsURL path parameters
webhook.headersRequest headers (lowercase keys)
webhook.filesUploaded files (multipart/form-data) with base64 buffers

For JSON request bodies, all top-level fields are also accessible directly:

// POST body: { "userId": 123, "action": "sync" }
{{ initial.userId }} // 123
{{ initial.action }} // "sync"
{{ initial.webhook.query.debug }} // query param ?debug=true

Form submissions spread the submitted field values to the root and include a form context:

{{ initial.name }}
{{ initial.email }}
{{ initial.form.formName }}
{{ initial.form.submittedAt }}
{{ initial.form.authenticatedUser.username }}

The form object contains:

FieldDescription
form.triggerIdThe trigger ID
form.formNameName of the form
form.submittedAtISO 8601 timestamp of submission
form.authenticatedUserPresent if the form requires authentication
form.authenticatedUser.usernameThe authenticated user’s username
form.authenticatedUser.connectionNameThe form-auth connection used
form.authenticatedUser.metadataCustom metadata from the form-auth connection

Scheduled workflows receive the initialData configured in the trigger settings, spread directly to the root:

// initialData config: { "reportType": "daily", "emailTo": "admin@example.com" }
{{ initial.reportType }} // "daily"
{{ initial.emailTo }} // "admin@example.com"

Event payloads from connected services are spread directly to the root of initial. The structure depends on the event provider:

{{ initial.eventType }}
{{ initial.data.agentId }}
{{ initial.data.newState }}

When executing a workflow manually or via API, the provided initial data is spread to the root:

// API call: POST /workflow-templates/:id/execute { "initial": { "name": "John" } }
{{ initial.name }} // "John"

The set-variable step writes values into $vars. Each set-variable step merges its output into the existing $vars object, so values persist and accumulate across the workflow:

{{ $vars.customerName }}
{{ $vars.retryCount | default: 0 }}

Reference connection credential objects by their connection name:

{{ $connections.my-salesforce }}
{{ $connections.my-crm.accessToken }}

See Connections for setup guides.

Reference encrypted environment variables. Variables from the workflow’s default environment are available at the root level:

{{ $env.API_KEY }}
{{ $env.DATABASE_URL }}

Variables from other environments are scoped by environment name:

{{ $env.staging.API_KEY }}

See Environments for details on setup and connection redirection.

$execution exposes the current run’s identity — useful for stamping side-effects (claimed rows, log lines, external API metadata) so they correlate back to a specific execution in traces or external systems.

FieldTypeDescription
$execution.idstringUnique execution ID (UUID) for the current run
$execution.workflowIdstringID of the workflow being executed (empty for ad-hoc / unsaved runs)
$execution.workflowNamestringHuman-readable workflow name
$execution.organizationIdstringOrganization running this execution
$execution.environmentstringEnvironment name (e.g. production, staging)
$execution.startedAtstringISO 8601 timestamp of when the execution started
{{ $execution.id }} // "8cc63dd9-5d0d-436f-aec6-113b66d36259"
{{ $execution.workflowId }} // "wf-customer-onboarding"
{{ $execution.startedAt }} // "2026-05-27T12:34:56.000Z"

A common use case: passing $execution.id as a correlation token to downstream systems (X-Request-Id headers, claim tokens, audit-log fields) so a row touched by this run can be traced back to it.

$errors is a running array of every operational and execution error that has occurred in the workflow up to the current step. Use it after Continue on Error to inspect what went wrong without having to remember which step failed.

Each entry has this shape:

{{ $errors | size }} // total entries so far
{{ $errors[0].stepId }} // step that produced the error
{{ $errors[0].type }} // 'operational' or 'execution'
{{ $errors[0].message }} // human-readable error message
{{ $errors[0].code }} // machine code (e.g., HTTP_CLIENT_ERROR)
{{ $errors[0].severity }} // 'error' or 'warning'

$errors is populated even when Continue on Error isn’t set — but in that case the workflow halts on the first error, so only the failing step’s entry is visible. With Continue on Error enabled on a step (or globally), downstream steps can branch on $errors to react to upstream failures.

When using data transformation steps like map, filter, or reduce, these variables are available within each iteration:

VariableDescription
{{ $item }}Current item being processed
{{ $original }}Original item before transformation
{{ $this }}Alias for $item (useful for primitives)
{{ $index }}Zero-based iteration index
{{ $isFirst }}true for the first item
{{ $isLast }}true for the last item

Example in a map step expression:

{{ $item.firstName }} {{ $item.lastName }} ({{ $index }})

Inside For Each step iterations (not data-transform rows), {{ $indexPath }} is also available — the array of iteration indexes across all enclosing loops. See Control Flow.