Skip to main content

Node Anatomy

Understand the structure of an ActionFlows node: its inputs, outputs, handles, configuration, and how data flows through it on the canvas.

Node Anatomy

A node is the unit of work on the canvas. This page covers inputs, outputs, handles, and how data moves through a node.

What You'll Learn: The complete structure of nodes, why they're different from competitors, and how to design workflows that don't break at runtime.


What is a Node?

A node is the fundamental unit of computation in ActionFlows. Think of it as a pure function with explicit inputs, outputs, and side effects.

┌─────────────────────────────────────────┐
│           NODE STRUCTURE                │
├─────────────────────────────────────────┤
│                                         │
│  INPUT        │                   OUTPUT│
│  HANDLES ────→│  [COMPUTATION]  ├────→ HANDLES
│               │                   │     
│  (LEFT SIDE)  │   (Process)      │ (RIGHT SIDE)
│               │                   │
└─────────────────────────────────────────┘

Properties:
✓ Receives typed inputs (left side)
✓ Performs single task (AI call, decision, data fetch)
✓ Produces typed outputs (right side)
✓ No state between executions (isolation)

In professional terms: Nodes are pure functions with deterministic side effects. Given the same inputs, they always produce the same outputs.


The Core Difference: ActionFlows vs Traditional Platforms

Traditional Approach: The Runtime Error Problem

Step 1: Start
    ↓ outputs loose JSON
Step 2: Node B receives it
    ↓ tries to parse
Step 3a: If parse fails
    ↓ ERROR AT RUNTIME (RED)
    (you don't catch it until the workflow runs)
Step 3b: If parse succeeds
    ↓ proceed (hope the structure is right)

The Problem:

Developer builds flow → Publishes to production → Flow runs on real data → Data structure is different than expected → Node fails silently or crashes → Customer support ticket created → Developer debugging at 2am

Cost: Debugging time, customer trust, system reliability.


Node Anatomy: Inputs & Outputs

Every node has left-side inputs and right-side outputs. These are called handles.

Input Handles (Data Flows In)

Start Input (Green Dot)

Control flow trigger that signals "Run this node when previous completes". This is implicit and not manually configured. Every node has one except Start nodes.

Data Inputs (Named Circles)

Specific data parameters like "Prompt", "Email Body", or "Topic". These can be connected from other nodes or hardcoded as static values.

Each input has a declared type:

Input Type System
├─ Text           (string, email, URL)
├─ Number         (integer, float, percentage)
├─ Boolean        (true/false)
├─ Object         (structured data with schema)
├─ Array          (list of items)
├─ File           (image, PDF, document)
└─ Enum           (predefined options)

Type Checking Rule:
Text output      → Text input        ALLOWED
Number output    → Text input        BLOCKED (type mismatch)
Object output    → Object input      ALLOWED (if schema matches)

Output Handles (Data Flows Out)

Every node produces at least one output. The type depends on node category:

AI Nodes Output:

Generate Text
├─ Generated Text (Text): AI response
├─ Token Count (Object): {input: 145, output: 287}
└─ Cost (Number): 0.003 USD

Connection Rules (The Platform's Safety Guardrails)

The Canvas Enforces Type Safety

You cannot connect incompatible handles. The platform makes it physically impossible to create invalid connections.

CONNECTION VALIDATION

Valid Connections (enabled, clickable):
├─ Text output → Text input
├─ Number output → Number input
└─ Object {customer} → Object {customer} input

Invalid Connections (dimmed, blocked):
├─ Number output → Text input (cannot click)
├─ Array output → Object input (cannot click)
└─ File output → Text input (cannot click)

Hovering over handle shows:
"Expected type: Text"
"This output: Number"
"INCOMPATIBLE"

Visual Feedback:

  • Green checkmark = connection valid
  • Red X = connection invalid
  • Hover shows expected vs. actual type

Node Categories: Anatomy & Patterns

Start Nodes (Triggers)

No inputs. They initiate execution.

START NODES
├─ Start
│  └─ Output: user_input (any type user provides)

├─ Start
│  ├─ from (Text)
│  ├─ subject (Text)
│  ├─ body (Text)
│  └─ attachments (Array of Files)

├─ flow webhook on Start
│  └─ payload (Object: raw request data)

├─ Schedule Trigger
│  ├─ timestamp (Number)
│  └─ schedule_metadata (Object)

└─ Database Watch
   └─ record_changed (Object)

Why Multiple Triggers Matter: Different integrations provide different data shapes. Explicit types prevent silent failures downstream.


AI Nodes

Inputs: Model choice, prompt, parameters, context data

Outputs: Generated content plus metadata (tokens, cost)

GENERATE TEXT NODE

Inputs:
├─ Model (Enum dropdown)
│  ├─ Claude Sonnet 4.5 (USD 3 per million input)
│  ├─ Claude Haiku 4.5 (USD 1 per million input)
│  ├─ GPT-4o (USD 2.50 per million input)
│  └─ Mistral Large (USD 2 per million input)

├─ Prompt (Text: your instruction)
│  └─ Can reference other outputs

├─ Temperature (Number: 0-2)
│  └─ 0 = deterministic, greater than 0 = creative

├─ Max Tokens (Number)
│  └─ Controls response length and cost

└─ System Prompt (Text: optional)
   └─ Instructions that apply to all calls

Outputs:
├─ Generated Text (Text)
│  └─ The AI response

├─ Token Count (Object)
│  ├─ input_tokens: 145
│  ├─ output_tokens: 287
│  └─ total_tokens: 432

└─ Cost (Number)
   └─ USD amount for this execution

Key Difference from Competitors:

n8n/Make:

AI call completes
Output: {response: "text"}
(cost hidden from flow)

ActionFlows:

AI call completes
Outputs: 
├─ text: "response"
├─ token_count: {input, output}
└─ cost: 0.003

You can use these in downstream logic:
"If cost greater than 0.01, send alert"
"Log token usage to database"

Control Nodes (Decision Logic)

If Node: Branching Logic

Inputs:
├─ Condition (Boolean)
│  └─ Example: sentiment score greater than 0.8

└─ Left and Right paths (implicit)
   └─ One executes, other skipped

Outputs:
├─ TRUE branch
│  └─ Executes if condition passes

└─ FALSE branch
   └─ Executes if condition fails

Visual Flow:
    [Condition Check]

      ┌──┴──┐
      │     │
    TRUE  FALSE
      │     │
    [Path1][Path2]
      │     │
      └──┬──┘
        [Merge]

Integration Nodes

🔗

Slack Node

Inputs: channel, message, blocks (formatting)

Outputs: message_id, status, timestamp

Cost: Free (integration only)

🗄️

Database Node

Inputs: operation, table, data, conditions

Outputs: record, records, row_count, error

Cost: Depends on your database pricing

🌐

HTTP Request Node

Inputs: URL, method, headers, body

Outputs: response, status_code, headers, error

Cost: Free (external API pricing applies)

📧

Email Node

Inputs: recipient, subject, body, attachments

Outputs: message_id, status, delivered_at

Cost: Free (email provider pricing applies)


Data Flow Through Nodes: Explicit Mapping

When you connect two nodes, you create an explicit mapping of which output feeds which input.

Email to Analyze to Slack

Step 1: Start fires
Output:
├─ sender: "[email protected]"
├─ subject: "Need help with order"
└─ body: "My order hasn't arrived..."

Step 2: Generate Text (AI Analysis)
Inputs:
├─ Prompt: "Analyze email and extract: sentiment, urgency, topic"
├─ Email context: from email trigger body

Outputs:
├─ analysis: {sentiment: "frustrated", urgency: "high", topic: "shipping"}
└─ cost: 0.002

Step 3: Slack Notification
Inputs:
├─ channel: "#support"
├─ message: "Priority ticket: frustrated customer with shipping issue"

Result:
Slack receives the complete message

What is Happening:

data_flow = {
  email.body → Generate Text
  → analysis.sentiment → Slack
  → analysis.urgency → Slack
}

Every connection explicit. No hidden mappings.

Variable References: The Syntax

Within any text field, reference outputs from other nodes with this syntax.

Syntax: {{nodeId.outputName}}

Examples:
├─ {{startNodeId.body}}
│  JSON body from a flow webhook, or a mapped start output
├─ {{generateTextNodeId.text}}
│  text output from Generate Text
└─ {{databaseNodeId.records}}
   array output; use the chip path UI for nested fields

The inspector inserts chips when you drop an output handle. Do not type a fictional Email Trigger node name.


Node Execution and State

Determinism Guarantee

Identical inputs result in identical outputs. Always.

Execution 1:
Input: "What is 2 plus 2?"
Model: Claude (temperature: 0)
Output: "4"

Execution 2 (same everything):
Input: "What is 2 plus 2?"
Model: Claude (temperature: 0)
Output: "4"

Execution 3 (change temperature to 0.7):
Input: "What is 2 plus 2?"
Model: Claude (temperature: 0.7)
Output: "The answer is four." ← different wording, same meaning

Why this matters:

  • Predictable behavior
  • Easier debugging
  • Safe for production
  • Cost predictability

No State Between Executions

Each execution is ISOLATED.

Run 1: node outputs "Hello"
Run 2: node outputs "Hi" (different prompt)
Run 3: node outputs "Hello" (same as Run 1)

There is NO memory:
"Hey, I ran before and output Hello"

Each run starts fresh.

If you NEED memory (count visits, track status):
Use Database node to store and retrieve

Execution Context (Implicit Access)

During execution, a node has access to:

Automatic Access:
├─ Its own inputs
├─ Previous node outputs
├─ Environment variables (credentials, API keys)
├─ Execution metadata
│  ├─ run_id (unique ID for this execution)
│  ├─ timestamp (when it ran)
│  ├─ attempt_number (for retries)
│  └─ user_id (who triggered it)

All automatic. You do not manually configure.

Advanced Patterns

Pattern One: Conditional Branching

Email Received

AI Sentiment Analysis
    ├─ Score greater than 0.8 (happy customer)
    │  └─ Route to: Slack celebrations

    ├─ Score 0.3 to 0.8 (neutral)
    │  └─ Route to: general-responses

    └─ Score less than 0.3 (upset customer)
       └─ Route to: urgent-support

       Alert manager and create ticket

Implementation:

If node checks: sentiment score greater than 0.8
├─ YES → Slack celebrations
└─ NO → Check next condition
   If score greater than 0.3
   ├─ YES → Slack general
   └─ NO → Priority support flow

Pattern Two: Parallel Execution (Speed Multiplier)

Customer Email Arrives

Three tasks RUN IN PARALLEL:

├─ Branch 1: AI sentiment analysis
│  └─ Executes: 2 seconds

├─ Branch 2: Database lookup (customer history)
│  └─ Executes: 300 milliseconds

└─ Branch 3: API call (inventory check)
   └─ Executes: 1.5 seconds

MERGE waits for slowest (2 seconds)

All results available simultaneously

Create comprehensive response

If serial (sequential):
└─ 2 seconds plus 0.3s plus 1.5s equals 3.8 seconds

If parallel (all together):
└─ maximum time equals 2 seconds
   Saves: 1.8 seconds per execution
   On 1,000 executions: 30 minutes saved

Pattern Three: Looping with Intelligence

Batch Process 1,000 Customer Records

Loop Node
├─ For each record:
│  ├─ AI analysis (2 seconds times 1,000 equals 33 mins)
│  ├─ Save result to database
│  └─ Count successes and failures

└─ Outputs per iteration:
   ├─ item (current record)
   ├─ index (1 to 1,000)
   └─ completed (when loop done)

After loop: Summary
├─ Processed: 1,000 records
├─ Successful: 998
├─ Errors: 2
└─ Total cost: USD 15.40

Node Performance: Critical Considerations

Execution Speed

  • AI Nodes: 1 to 10 seconds per call (slow)
  • Database: 100 to 500 milliseconds (medium)
  • Control: less than 10 milliseconds (fast)

Strategy: Minimize AI calls. Batch when possible.

💰

Token Cost

  • Short prompt: USD 0.001
  • Long context: USD 0.05 to 0.50
  • Image generation: USD 0.02 to 0.20 per image

Strategy: Use cheaper models (Haiku). Cache results.

💾

Memory Limits

  • Array size: Max 10,000 items
  • Text: Max 1,000,000 characters
  • API response: Max 50 megabytes

Strategy: Paginate large queries. Stream results.


Optimization Examples

Bad: AI in Every Loop Iteration

Loop through 100 customer emails:
├─ Iteration 1: AI analysis (3s) equals USD 0.005
├─ Iteration 2: AI analysis (3s) equals USD 0.005
├─ Iteration 3: AI analysis (3s) equals USD 0.005
├─ and so on
└─ Iteration 100: AI analysis (3s) equals USD 0.005

Total time: 5 minutes
Total cost: USD 0.50

Problem: Slow and expensive. Long wait times for user.


Side-by-Side: ActionFlows vs n8n

Type Safety

n8n:

Node outputs JSON (untyped)
Connected node receives it
If structure wrong equals runtime error
You debug in production

ActionFlows:

Node declares output type
Connected node declares required type
If mismatch equals linter error (before publish)
You fix it in development

Winner: ActionFlows (catch errors early)


Node Design Best Practices

Keep Nodes Focused

One node equals one job. Not mixing concerns.

GOOD:
├─ Start (just reads email)
├─ AI Analysis (just analyzes)
└─ Slack Send (just sends)

BAD:
└─ Start that also analyzes plus sends to Slack

Use Descriptive Names

GOOD: "Classify Support Ticket Sentiment"
BAD: "AI Process"

GOOD: "Extract Customer Email from HTML"
BAD: "Extract Data"

Self-documenting flows are easier to maintain.

Handle Errors Explicitly

Every node that can fail should branch:
├─ Success path
└─ Error path (log, alert, retry)

Do not ignore errors. Route them explicitly.

Test Before Production

1. Configure the node on the Actionflow Studio canvas
2. Run the whole flow with sample data
3. Verify outputs on the node and in Run Output
4. Check cost on that run
5. Adjust wiring or prompts, then run again

Map Data Deliberately

Do not rely on implicit data passing.

GOOD: Explicitly reference node outputs
BAD: Assume system figures it out

Explicit equals safer plus easier to debug

Quick Reference: Node Anatomy Cheat Sheet

TermDefinitionExample
Input HandleData enters herePrompt input
Output HandleData exits hereGenerated Text
Data TypeKind of dataEmail Body equals Text
ConnectionLink output to inputText output to Text input
MappingAssign outputs to inputsresult to message
Start InputExecution triggerWhen to run this node
Pure FunctionSame input equals same outputDeterministic
Side EffectExternal actionSend email
DeterminismRepeatable behaviorTemperature equals zero
State IsolationNo memory between runsEach run is fresh
Execution ContextAuto available metadatarun_id, timestamp
Type ValidationCheck compatibilityNo runtime surprises
Streaming OutputReal-time feedbackUser sees response live
Parallel ExecutionMultiple nodes togetherFaster workflows
Error HandlingExplicit error routingTry to success or error

Next: Explore Node Types in Depth

🤖

AI Nodes

Generate Text, Generate Image, Transcribe Audio, Generate JSON. Model selection, streaming, structured outputs.

Explore AI Nodes

🔀

Control Nodes

If, Loop, Merge, Wait, Uniq. Decision logic, iteration, synchronization, branching.

Explore Control Nodes

🔗

Integration Nodes

Slack, Email, Database, HTTP Request, Webhooks. Connect to external systems.

Explore Integrations

Actionflow Studio

Actionflow Studio is the flow editor. Configure the node, then run the whole graph to see outputs and cost.

Open Actionflow Studio


You now understand node anatomy.

This foundation powers everything in ActionFlows. When you build workflows, you are orchestrating these principles. Start building.

On this page