Use variables and Liquid safely
Practical examples for workflow inputs, step outputs, Liquid filters, arrays, and For Each mappings.
Variables are how workflow tasks pass data to each other. Liquid is the template syntax you use to insert those values into task fields, prompts, messages, and mappings.
What You'll Learn
You will learn how to:
- Reference workflow inputs.
- Reference prior step outputs.
- Use Liquid filters like
jsonandjson_compact. - Pass arrays into For Each.
- Avoid the most common variable mistakes.
When to Use This
Use this guide when a workflow field accepts variables, especially AI Prompt, Update Record, Slack Message, Send Email, For Each, Nested Workflow, and integration tasks.
Estimated time: 10-15 minutes.
Concepts used: Variables, Tasks, Workflows.
1. Reference Workflow Inputs
Workflow inputs are values provided by the caller: a trigger, manual run, agent tool call, parent workflow, or batch run.
Example:
{{ inputs.account_id }}Use inputs for values the workflow needs before any task runs:
account_idcontact_idopportunity_idcampaign_idsearch_criteria
If an input is required, every caller must map or provide it.
2. Reference Step Outputs
Task outputs are available under steps.<step_number>.*.
Example:
{{ steps.1.account.name }}Common patterns:
{{ steps.1.account.domain }}
{{ steps.2.result }}
{{ steps.3.summary }}
{{ steps.4.enriched_email }}Use the variable picker whenever possible. It knows which variables exist at that point in the graph and helps avoid typos.
3. Use Variables in Prompts
AI Prompt tasks often combine record data and prior task output.
Example:
Write a two-sentence account angle.
Account:
{{ steps.1.account.name }}
Domain:
{{ steps.1.account.domain }}
Research:
{{ steps.2.result }}Keep prompts explicit about the output you want. If a downstream task needs structured data, configure structured output instead of parsing free text later.
4. Use JSON Filters for Objects
When you pass an object into a prompt, message, or integration task, render it as JSON.
Readable JSON:
{{ steps.1.account | json }}Compact JSON:
{{ steps.2.object | json_compact }}Use json when humans will read the prompt or debug output. Use json_compact when a task field expects compact JSON.
5. Pass Arrays into For Each
The For Each task expects an array.
If Find Prospects returns an array under its output key, pass that array directly:
{{ steps.1.prospects }}Do not pass a single item or a wildcard-style sub-path unless the task specifically expects it. If the variable picker marks a value with an array badge, that is usually the safest choice for For Each.
6. Map Parent Workflow Values into Nested Workflows
Nested Workflow and For Each tasks call another workflow. The parent workflow must map values into the child workflow's inputs.
Example mapping:
| Child input | Parent value |
|---|---|
contact_id | {{ item.contact_id }} |
account_id | {{ inputs.account_id }} |
campaign_id | {{ inputs.campaign_id }} |
Keep child workflow inputs small and explicit. It is easier to debug a child workflow that expects contact_id than one that expects a giant mixed object.
7. Use Conditional Logic Sparingly
Liquid supports simple conditional logic:
{% if steps.2.score > 80 %}
High priority
{% else %}
Normal priority
{% endif %}Use conditionals for small formatting decisions. If the workflow needs a real branch, use a workflow control-flow task instead so the branch is visible in the graph.
8. Debug Variable Problems
If a variable does not resolve:
- Check the step number.
- Open the prior step output and confirm the field exists.
- Use the variable picker instead of typing by hand.
- Open the Diagnostics tab.
- Confirm the caller mapped required workflow inputs.
Common broken references:
{{ trigger.record_id }}Use this instead after mapping trigger output to workflow input:
{{ inputs.record_id }}{{ steps.account.name }}Use the numeric step namespace:
{{ steps.1.account.name }}Success Check
You are done when:
- Diagnostics show no invalid variable references.
- Every required workflow input is mapped by its caller.
- For Each receives an array.
- Objects passed to integration tasks use the right JSON filter.
- Test runs show expected rendered values in step inputs.
Common Pitfalls
- Using the old implicit
{{ trigger.* }}namespace. - Referencing a step that runs later in the graph.
- Passing a whole object when a task expects a string id.
- Passing text that looks like JSON instead of actual rendered JSON.
- Hiding complex branching logic in Liquid instead of using workflow tasks.