Athena
Home
Environments
Environments
  • Development Server
  • Production
Home
Environments
Environments
  • Development Server
  • Production
  1. Workflows
  • Getting Started
    • Start Guide
  • Installation & Setup
    • Windows
  • Architecture
  • Guide
    • Bundles
      • Backend
    • Permissions
      • Frontend
    • Developers
      • Commit Lint
      • RESTful API
    • Workflows
      • Workflow Variables
  • API Reference
    • Authentication
      • Sign In
      • Logout
    • User
      • Get Authenticated User using Multiplai App Access Token
      • Get Authenticated User using Basic Token
    • Workspace
      • Get Workspaces Metrics
      • Get Workspaces
      • Update a Workspace
      • Retrieve a workspace
      • Delete a Workspace
    • Provider
      • Get Providers
      • Retrieve a Provider
      • Update a Provider
      • Create a Provider
      • Delete a Provider
    • Account
      • Get Accounts
      • Update an Account
      • Create an Account
      • Delete an Account
      • Retrieve an Account
    • Agent
      • Get Agents
      • Update an Agent
      • Create an Agent
      • Delete an Agent
      • Retrieve an Agent
      • Run an Agent
      • Train an Agent
      • Generate an Agent
      • Share Agent
      • Get Agent Leaderboard
    • Workflow
      • Get Workflows
      • Create a Workflow
      • Retrieve a Workflow
      • Update a Workflow
      • Delete a Workflow
      • Trigger a webhook
      • Share Workflow
      • Generate Workflow
    • Workflow Execution
      • Get Workflow Executions
      • Get Workflow Execution Counts
      • Retrieve a Workflow Execution
      • Delete a Workflow Execution
    • Prompt
      • Get Prompts
      • Create a Prompt
      • Retrieve a Prompt
      • Update a Prompt
      • Delete a Prompt
      • Run a prompt
    • Memory
      • Get Memories
      • Retrieve a Memory
      • Update a Memory
      • Delete a Memory
    • Thread
      • Get Threads
      • Retrieve a Thread
      • Update a Thread
      • Delete a Thread
      • Create a Thread
      • Run a Thread
      • Generate Thread Name
    • Message
      • Get Messages
      • Retrieve a Message
      • Update a Message
      • Delete a Message
      • Create a Message
    • Large Language Model
      • Get Large Language Models
      • Retrieve a Large Language Model
    • Command Room Task
      • Store Command Room Task
      • Remove Command Room Task
    • Metrics
      • Get Agents Metrics
      • Get Workflows Metrics
      • Get Threads Metrics
      • Get Messages Metrics
      • Get Workflow Executions Metrics
  • Schemas
    • Resources
      • User
      • Workspace
      • Provider
      • Account
      • Agent
      • Workflow
      • Share
      • WorkflowExecution
      • WorkflowExecutionData
      • Prompt
      • Memory
      • Thread
      • Attachment
      • Media
      • Tool
      • Message
      • LargeLanguageModel
      • AgentLeaderboard
    • Utils
      • Pagination
        • PaginationMeta
        • PaginationLinks
      • Provider
        • AuthenticationConfig
      • Profile
        • ProfilePhotoConfig
      • Workflow
        • WorkflowExecutionDataWorkflowData
        • Node
        • Edge
  1. Workflows

Workflow Variables

Workflow Variables: User Guide#

Overview#

Workflow variables allow you to pass data between nodes dynamically. Instead of hardcoding values, you can reference outputs from previous nodes, creating flexible data pipelines that adapt to your data.
This guide shows you how to write and use variables in your workflows.

Table of Contents#

1.
Variable Syntax
2.
Basic Patterns
3.
Advanced Patterns
4.
Practical Examples
5.
Best Practices
6.
Troubleshooting
7.
Common Failure Patterns & Debugging
8.
Quick Reference

What Are Variables?#

Variables are placeholders in your node parameters that get replaced with actual data when the workflow runs. They're written using double curly braces: {{variablePath}}
Simple Example:
{
    "id": "sendEmail",
    "parameters": {
        "to": "{{getUserProfile.item.email}}",
        "subject": "Welcome {{getUserProfile.item.name}}!"
    }
}
When the workflow runs, {{getUserProfile.item.email}} is replaced with the actual email from the getUserProfile node's output.

Variable Syntax#

Basic Format#

All variables use double curly braces: {{variablePath}}
{
    "message": "{{previousNode.item.message}}",
    "count": "{{previousNode.all.length}}",
    "mixed": "Hello {{user.name}}, you have {{notifications.count}} new messages"
}

Where Can You Use Variables?#

You can use variables in any node parameter that accepts text or values:
{
    "parameters": {
        "email": "{{user.item.email}}",           // Text field
        "count": "{{users.count()}}",              // Number field
        "data": "{{previousNode.item}}",           // Object/Array field
        "url": "https://api.com/{{user.item.id}}" // Part of a string
    }
}

Basic Patterns#

Pattern 1: Reference the Previous Node#

Use input to access data from the node that just executed before the current node.

{{input.item}} - Current Item#

Gets the current item being processed from the previous node.
When to use: When the previous node returns multiple items and your node runs once per item.
Example:
// Previous node returned: [
//   { "id": 1, "name": "Alice" },
//   { "id": 2, "name": "Bob" }
// ]

{
    "id": "sendEmail",
    "parameters": {
        "to": "{{input.item.email}}",     // Gets email of current item
        "name": "{{input.item.name}}"     // Gets name of current item
    }
}

// First run: to = "alice@example.com", name = "Alice"
// Second run: to = "bob@example.com", name = "Bob"

{{input.all}} - All Items#

Gets all items from the previous node as an array.
When to use: When you need to process the entire dataset at once.
Example:
// Previous node returned: [
//   { "score": 85 },
//   { "score": 92 }
// ]

{
    "id": "aggregate",
    "parameters": {
        "allScores": "{{input.all}}"  // Gets entire array
    }
}

// allScores = [{ "score": 85 }, { "score": 92 }]

Pattern 2: Reference Any Node by ID#

Use a node's ID to access its output, even if it's not the immediately previous node.

{{nodeId.item}} - Latest Item from Specific Node#

Gets the most recent item from a specific node's output.
When to use: When you need data from a node that's not directly before the current one.
Example:
// Workflow: fetchUser → calculateTotal → sendEmail

{
    "id": "sendEmail",
    "parameters": {
        "to": "{{fetchUser.item.email}}",        // From fetchUser node
        "amount": "{{calculateTotal.item.total}}" // From calculateTotal node
    }
}

{{nodeId.all}} - All Items from Specific Node#

Gets all items from a specific node's output.
When to use: When you need the complete dataset from a specific node.
Example:
{
    "id": "mergeData",
    "parameters": {
        "users": "{{fetchUsers.all}}",    // All users from fetchUsers
        "orders": "{{fetchOrders.all}}"   // All orders from fetchOrders
    }
}

Pattern 3: Access Nested Properties#

Use dot notation to navigate into nested objects and arrays.
Example:
// API returned: {
//   "user": {
//     "profile": {
//       "firstName": "Jane",
//       "lastName": "Doe"
//     },
//     "addresses": [
//       { "street": "123 Main St", "city": "Boston" }
//     ]
//   }
// }

{
    "parameters": {
        "firstName": "{{apiCall.item.user.profile.firstName}}",      // "Jane"
        "street": "{{apiCall.item.user.addresses.0.street}}",        // "123 Main St"
        "city": "{{apiCall.item.user.addresses.0.city}}"             // "Boston"
    }
}

Array Index Access#

Use numbers to access specific items in an array:
"{{nodeId.item.items.0}}"     // First item (index 0)
"{{nodeId.item.items.1}}"     // Second item (index 1)
"{{nodeId.item.items.2}}"     // Third item (index 2)

Variable Syntax Deep Dive (Input-First Convention)#

This project standard uses {{input.item...}} as the default syntax in node parameters.

Syntax Decision Matrix#

ContextPreferred SyntaxUse It ForExample
Previous node (current item){{input.item...}}Most node fields{{input.item.email}}
Previous node (all items){{input.all}}Batch operations, aggregate input{{input.all}}
Specific node (current item){{nodeId.item...}}Cross-branch or non-adjacent node reference{{fetchUser.item.name}}
Specific node (all items){{nodeId.all}}Full dataset from another node{{fetchOrders.all}}
Loop context (inside loop path){{$loop...}}Iteration metadata + current iterated item{{$loop.index}}, {{$loop.item.id}}
Workflow constants{{$vars...}}Reusable global config values{{$vars.base_url}}
Environment variables{{$env...}}Secrets/config from environment{{$env.API_BASE_URL}}
Direct node handle (advanced){{$node["Node Name"]...}}Dynamic cross-node lookups when needed{{$node["HTTP Request"].item.result}}
Code node script$input (JavaScript)Programmatic transformations in codeconst item = $input.all()[0].json;

What Are $loop, $vars, $node, $env?#

$loop (Loop Over Items context)#

Available when executing inside the loop branch:
{
    "currentIndex": "{{$loop.index}}",
    "totalItems": "{{$loop.count}}",
    "currentItemId": "{{$loop.item.id}}"
}
Use $loop when you need iteration metadata. Use {{input.item...}} for standard field access in most non-loop nodes.

$vars (Workflow-scoped variables)#

Reusable constants set for the workflow:
{
    "url": "{{$vars.api_base_url}}/customers/{{input.item.customer_id}}",
    "workspace": "{{$vars.workspace_uuid}}"
}
Use $vars for non-changing values you do not want to duplicate across nodes.

$node (Read output from a named node)#

Advanced reference by node name:
{
    "customerEmail": "{{$node[\"fetchCustomer\"].item.email}}",
    "orderTotal": "{{$node[\"calculateTotal\"].item.total}}"
}
Use {{nodeId.item...}} first. Use $node[...] only when you specifically need name-based dynamic lookups.

$env (Environment-level values)#

Configuration from runtime environment:
{
    "base_url": "{{$env.APP_URL}}",
    "api_key": "{{$env.EXTERNAL_API_KEY}}"
}
Use $env for deployment/runtime config and secrets. Do not hardcode secrets in workflow JSON.

How Syntax Changes by Node Type#

Node TypeRecommended Access Pattern
HTTP Request, Edit Fields, Filter, If, Switch, Table nodes{{input.item...}}
Aggregate, Merge, batch operations{{input.all}} or {{nodeId.all}}
Loop Over Items branch{{input.item...}} + {{$loop...}} when iteration metadata is needed
Code nodeUse $input in JavaScript, return clean object shape

Common Mistakes (and Fixes)#

1.
Using a specific node reference when input is enough
Prefer: {{input.item.email}}
Only use {{nodeId.item.email}} when reading from a non-previous node.
2.
Forgetting loop context exists only inside loop execution
{{$loop.index}} works in loop path, not outside it.
3.
Mixing typed values with string text unintentionally
{{input.item.count}} keeps number type.
"Count: {{input.item.count}}" becomes string.
4.
Using deep paths without testing intermediate objects
Validate step-by-step: {{input.item}} -> {{input.item.user}} -> {{input.item.user.email}}.
5.
Putting secrets directly in node params
Use {{$env.SECRET_NAME}} instead of raw secret strings.

Advanced Patterns#

Collection Methods#

Transform arrays using built-in methods. Use the $('nodeId') syntax:
Common Methods:
MethodDescriptionExample
first()Get first item{{$('users').first()}}
last()Get last item{{$('users').last()}}
count()Count items{{$('users').count()}}
pluck('field')Extract field from all items{{$('users').pluck('email')}}
sum()Sum numeric values{{$('orders').pluck('total').sum()}}
unique()Remove duplicates{{$('tags').unique()}}
take(n)Get first n items{{$('users').take(5)}}
sortBy('field')Sort by field{{$('users').sortBy('name')}}
Example:
// users = [
//   { "name": "Alice", "email": "alice@example.com", "age": 30 },
//   { "name": "Bob", "email": "bob@example.com", "age": 25 }
// ]

{
    "parameters": {
        "emails": "{{$('users').pluck('email')}}",          // ["alice@...", "bob@..."]
        "count": "{{$('users').count()}}",                  // 2
        "firstEmail": "{{$('users').pluck('email').first()}}",  // "alice@example.com"
        "avgAge": "{{$('users').pluck('age').avg()}}"       // 27.5
    }
}

String Interpolation#

Embed multiple variables in a single string.
Mix variables with regular text:
{
    "parameters": {
        "greeting": "Hello {{user.item.name}}!",
        "message": "You have {{notifications.count}} new messages",
        "url": "https://api.com/users/{{user.item.id}}/profile"
    }
}

// Result:
// greeting = "Hello Alice!"
// message = "You have 5 new messages"
// url = "https://api.com/users/123/profile"

Type Preservation#

Important: When a variable is alone (not mixed with text), it keeps its original type:
{
    "parameters": {
        "count": "{{users.count()}}",           // Number: 42
        "isActive": "{{user.item.active}}",     // Boolean: true
        "tags": "{{post.item.tags}}",           // Array: ["tech", "ai"]
        "message": "Count: {{users.count()}}"   // String: "Count: 42"
    }
}

Special Variable: Static Data#

Access workflow-level constants using staticData:
{
    "parameters": {
        "apiKey": "{{staticData.apiKey}}",
        "baseUrl": "{{staticData.apiUrl}}"
    }
}

Special Variable: Human-in-the-Loop#

When a workflow includes a Human-in-the-Loop node, access user responses:
{
    "parameters": {
        "approved": "{{humanInTheLoop.item.approved}}",
        "comments": "{{humanInTheLoop.item.comments}}"
    }
}

$toBinary() Function#

Convert a URL to base64 encoding:
{
    "parameters": {
        "imageData": "$toBinary({{imageUrl.item.url}})"
    }
}
Limitations:
Only HTTPS URLs
Max 50MB file size

Practical Examples#

Example 1: Simple Data Passing#

// Workflow: Fetch User → Send Email

// Node 1: Fetch User
{
    "id": "fetchUser",
    "type": "http",
    "parameters": {
        "url": "https://api.example.com/users/123"
    }
}
// Output: { "name": "Alice", "email": "alice@example.com" }

// Node 2: Send Email
{
    "id": "sendEmail",
    "type": "email",
    "parameters": {
        "to": "{{fetchUser.item.email}}",        // "alice@example.com"
        "subject": "Hello {{fetchUser.item.name}}"  // "Hello Alice"
    }
}

Example 2: Working with Arrays#

// Workflow: Get Table Rows → Process Each Row

// Node 1: Get Table Rows
{
    "id": "getTableRows",
    "type": "getTableRows",
    "parameters": {
        "table_uuid": "abc-123"
    }
}
// Output: [
//   { "id": 1, "name": "Item 1" },
//   { "id": 2, "name": "Item 2" }
// ]

// Node 2: Process Each Row (runs twice, once per item)
{
    "id": "processRow",
    "type": "http",
    "parameters": {
        "url": "https://api.example.com/items/{{input.item.id}}",
        "body": {
            "name": "{{input.item.name}}"
        }
    }
}
// First run: url = ".../items/1", body = { "name": "Item 1" }
// Second run: url = ".../items/2", body = { "name": "Item 2" }

Example 3: Combining Multiple Sources#

// Workflow: Fetch User → Fetch Orders → Send Summary

// Node 1: Fetch User
{
    "id": "fetchUser",
    "parameters": { "userId": "123" }
}
// Output: { "name": "Alice", "email": "alice@example.com" }

// Node 2: Fetch Orders
{
    "id": "fetchOrders",
    "parameters": { "userId": "123" }
}
// Output: [
//   { "id": "order1", "total": 50 },
//   { "id": "order2", "total": 75 }
// ]

// Node 3: Send Summary
{
    "id": "sendSummary",
    "parameters": {
        "to": "{{fetchUser.item.email}}",
        "name": "{{fetchUser.item.name}}",
        "orderCount": "{{$('fetchOrders').count()}}",
        "totalSpent": "{{$('fetchOrders').pluck('total').sum()}}"
    }
}
// to = "alice@example.com"
// name = "Alice"
// orderCount = 2
// totalSpent = 125

Example 4: Conditional Logic with If Node#

// Workflow: Fetch User → Check Age → Send Appropriate Message

// Node 1: Fetch User
{
    "id": "fetchUser"
}
// Output: { "name": "Bob", "age": 17 }

// Node 2: Check Age (If Node)
{
    "id": "checkAge",
    "type": "if",
    "parameters": {
        "condition": "{{fetchUser.item.age}} >= 18"
    }
}
// Output (partitioned):
// {
//   "true": [],     // Age >= 18
//   "false": [...]  // Age < 18
// }

// Node 3a: Adult Message (connected to "true" port)
{
    "id": "adultMessage",
    "parameters": {
        "message": "Welcome {{fetchUser.item.name}}! You have full access."
    }
}

// Node 3b: Minor Message (connected to "false" port)
{
    "id": "minorMessage",
    "parameters": {
        "message": "Sorry {{fetchUser.item.name}}, you must be 18 or older."
    }
}


Best Practices#

1. Use Clear Node IDs#

// ❌ Bad: Generic IDs
{ "id": "node1" }
{ "id": "node2" }

// ✅ Good: Descriptive IDs
{ "id": "fetchUserProfile" }
{ "id": "calculateOrderTotal" }

2. Use input for Simple Sequential Workflows#

// ✅ Good for simple chains
"{{input.item.result}}"

// ✅ Good when combining multiple sources
"{{fetchUser.item.email}}" and "{{calculateTotal.item.amount}}"

3. Test Variables Incrementally#

Build complex paths step by step:
// Step 1: Test the node output
"{{apiCall.item}}"

// Step 2: Navigate to nested object
"{{apiCall.item.data}}"

// Step 3: Access specific property
"{{apiCall.item.data.user}}"

// Step 4: Get final value
"{{apiCall.item.data.user.email}}"

4. Use Collection Methods Instead of Code#

// ❌ More Complex
{
    "type": "code",
    "parameters": {
        "code": "return items.map(item => item.email)"
    }
}

// ✅ Simpler
{
    "parameters": {
        "emails": "{{$('users').pluck('email')}}"
    }
}

5. Remember Type Preservation#

// ✅ Preserves type
"count": "{{users.count()}}"           // Results in number: 42

// ❌ Converts to string
"count": "Total: {{users.count()}}"    // Results in string: "Total: 42"

6. Keep Paths Shallow#

// ❌ Too deep (hard to debug)
"{{node1.item.data.user.profile.settings.preferences.theme}}"

// ✅ Reasonable depth
"{{node1.item.user.theme}}"

7. Document Complex Variables#

// Add comments to explain complex variable paths
{
    "parameters": {
        // Gets the email of the user who created the order
        "creatorEmail": "{{order.item.metadata.createdBy.user.email}}"
    }
}

Troubleshooting#

Issue 1: Variable Returns Null#

Problem: Variable resolves to null or empty
Common Causes:
Node ID is misspelled
Property path is wrong
Node hasn't executed yet (check workflow order)
Node execution failed
How to Fix:
1.
Test the base variable first: {{nodeId.item}}
2.
Gradually add depth: {{nodeId.item.data}}
3.
Check the node actually outputs that property
4.
Verify node ID matches exactly (case-sensitive)

Issue 2: Getting Wrong Data Type#

Problem: Expected a number but got a string
Cause: Mixing variables with text converts everything to string
Fix:
// ❌ Wrong: Returns "Count: 42" (string)
"count": "Count: {{users.count()}}"

// ✅ Right: Returns 42 (number)
"count": "{{users.count()}}"

Issue 3: Array Index Error#

Problem: Trying to access items.5 but array only has 3 items
Fix: Use collection methods that handle missing data:
// ❌ May return null
"{{data.item.items.10}}"

// ✅ Safer
"{{$('data').pluck('items').flatten().take(10)}}"

Issue 4: Wrong Data from If Node#

Problem: Getting data from wrong branch of If node
Cause: The connection (edge) between nodes needs a sourceHandle property
Fix: Ensure your edge specifies which output port ("true" or "false"):
{
    "source": "ifNode",
    "sourceHandle": "true",  // or "false"
    "target": "nextNode"
}

Debugging Tips#

Start Simple, Add Complexity:
// 1. Test basic access
"{{nodeId.item}}"

// 2. Add one level
"{{nodeId.item.data}}"

// 3. Add specific property
"{{nodeId.item.data.email}}"
Use a Code Node to Debug:
{
    "type": "code",
    "parameters": {
        "code": "const item = $input.all()[0].json; console.log(item); return item;"
    }
}
This will show you the exact structure of the data available.

Common Failure Patterns & Debugging (Production)#

This section focuses on what breaks most often in real workflows and how to diagnose failures quickly.

Production-Derived Patterns (From Internal Bug Investigations)#

Based on internal workflow bug investigations (including MAP-1369), these are the highest-impact failure patterns:

Top 10 Failure Patterns#

#Failure PatternWhat You SeeWhy It HappensFast Fix
1Wrong variable path depthEmpty/null valuesPath assumes fields that do not exist at runtimeValidate path incrementally: {{input.item}} -> nested levels
2Referencing wrong source nodeCorrect shape, wrong dataUsing {{nodeId.item...}} from stale/non-adjacent branchPrefer {{input.item...}} when sequential; use explicit node ID only when needed
3Loop context misuseIndex/item undefined{{$loop...}} used outside loop branchUse {{$loop...}} only inside loop execution path
4Array index out of boundsNull at deep array pathHardcoded index (for example .10) does not existCheck size first or use safer collection operations
5Type coercion surprisesNumeric comparisons failValue turned into string via interpolation in textKeep value standalone: {{input.item.count}} (not "Count: {{...}}")
6Hidden branch mismatchWorkflow "works" but outputs unexpected fieldsIf/Switch route differs from expected branchVerify branch condition and connected sourceHandle
7Generic error masking root causeSame error for many issuesNode reports one generic failure messageAdd context-specific checks and logging before critical node
8Upstream node partial failureDownstream fails inconsistentlyPrior node output shape changes on error/partial resultsNormalize payload with Edit Fields before critical references
9Environment/config mismatchWorks locally, fails in staging/prodMissing or different {{$env...}} valuesValidate required environment variables per environment
10Missing execution observability"Intermittent" failure with no cluesNo intermediate inspection/loggingAdd temporary debug nodes and structured logs during investigation

What Causes Silent Failures?#

Silent failures are usually "valid execution with wrong data," not hard crashes.
Most common silent-failure causes:
Variable resolves to empty/null and downstream node still accepts it
Branch condition evaluates unexpectedly (string/number mismatch)
Node succeeds with partial output, but missing fields are never validated
Wrong node reference returns old-but-valid data shape
Data transformed to string unintentionally, breaking later numeric logic
Add explicit validation nodes before critical actions:
If {{input.item.requiredField}} is empty -> route to error handling
If type is wrong -> stop flow with clear diagnostic message

Debugging Variable References That Don't Work (Playbook)#

Use this exact flow:
1.
Confirm execution order
Ensure source node runs before target node.
2.
Inspect the whole input first
Test with {{input.item}} in a safe field/output.
3.
Drill down one level at a time
{{input.item.data}} -> {{input.item.data.user}} -> {{input.item.data.user.email}}
4.
Check branch context
If inside loop, test {{$loop.index}} and {{$loop.item}}
If after If/Switch, verify correct output branch connection
5.
Validate data type assumptions
Keep numeric/boolean values standalone (not mixed with text).
6.
Compare input vs explicit node reference
If {{input.item.id}} fails, try {{sourceNode.item.id}} to verify source mismatch.
7.
Add temporary debug node
Use a Code node to log current item and pass it through:
{
    "type": "code",
    "parameters": {
        "code": "const item = $input.all()[0].json; console.log('DEBUG_ITEM', item); return item;"
    }
}
8.
Normalize before critical nodes
Use Edit Fields to create stable field names and shallow paths.

How to Read Error Messages Quickly#

Use this interpretation order:
1.
Node that failed: identifies where the symptom appears (not always root cause).
2.
Parameter name: points to the exact field with bad variable/path/type.
3.
Expected vs received type/value: reveals coercion or null-path issues.
4.
Execution context: check if failure occurred in loop, branch, or merged path.
5.
Previous node output shape: compare runtime shape to what your path expects.
When messages are generic:
Add local guards (If node checks) before the failing node.
Add temporary structured logs for key IDs and resolved values.
Replace one generic failure path with multiple specific diagnostic branches.

Can You See Intermediate Node Outputs During Execution?#

Yes. You should inspect intermediate outputs during debugging, especially before and after:
Loop Over Items
If/Switch branch splits
Merge/Aggregate nodes
Any node that mutates structure (Edit Fields, Code)
Recommended inspection workflow:
First inspect source node output shape
Then inspect immediate downstream node input assumptions
Add temporary pass-through debug Code nodes in between if needed
Remove debug nodes after resolution

Real-World Lesson from MAP-1369#

A production issue showed that intermittent workflow failures are often caused by context/state mismatches plus weak diagnostics, not just "bad data."
Practical takeaways:
Test dynamic variable paths that mirror real runtime payloads
Add branch-aware and loop-aware checks
Prefer specific error messages over generic ones
Add minimal debug logging during rollout for faster incident triage


Quick Reference#

What You WantPatternExample
Data from previous node (current item){{input.item}}{{input.item.email}}
All data from previous node{{input.all}}{{input.all}}
Data from specific node (latest item){{nodeId.item}}{{fetchUser.item.name}}
All data from specific node{{nodeId.all}}{{fetchUsers.all}}
Nested property{{node.item.path.to.value}}{{user.item.profile.age}}
Array element by index{{node.item.array.0}}{{data.item.items.2.name}}
Count items{{$('nodeId').count()}}{{$('users').count()}}
Extract property from all items{{$('nodeId').pluck('field')}}{{$('orders').pluck('total')}}
Sum values{{$('nodeId').pluck('field').sum()}}{{$('sales').pluck('amount').sum()}}
Get first item{{$('nodeId').first()}}{{$('users').first()}}
Workflow constant{{staticData.key}}{{staticData.apiKey}}
Human approval response{{humanInTheLoop.item.field}}{{humanInTheLoop.item.approved}}
Convert URL to base64$toBinary(url)$toBinary({{img.item.url}})

Key Concepts Summary#

1.
Two Access Patterns: Use input for previous node, use nodeId for any specific node
2.
Two Data Scopes: Use .item for single/current item, use .all for entire array
3.
Type Preservation: Variable alone keeps type, variable in text becomes string
4.
Collection Methods: Use $('nodeId').method() to transform arrays
5.
Dot Notation: Navigate nested objects with dots: object.property.subProperty
6.
Array Access: Use numbers for array indices: array.0, array.1, array.2

Need Help?#

Node Documentation: Check docs/workflow-nodes/ for what each node outputs
Test First: Build variable paths incrementally starting with {{nodeId.item}}
Use Code Nodes: Add a code node with const item = $input.all()[0].json; console.log(item) to inspect data structure

Document Version: 2.0 (User Guide)
Last Updated: February 17, 2026
Author: Athena Development Team
Modified at 2026-02-26 23:42:15
Previous
RESTful API
Next
Authentication
Built with