Action Nodes

Non-LLM programmatic nodes for deterministic workflow operations. Action nodes complement LLM agents by handling data transformation, API integrations, control flow, and automation logic.

Overview

Action nodes are visually distinct from LLM agent nodes — they use unique colors and icons to make workflows easy to scan. Each node type handles a specific category of operation, from HTTP requests to database queries to conditional branching.

All action nodes share a set of standard properties for error handling, tracing, execution control, and I/O mapping. They support {{variable}} interpolation in string fields and automatically receive predecessor node outputs.

Action Nodes Workflow

Available Nodes

NodeIconColorDescription
Trigger🎯IndigoWorkflow entry point (manual, webhook, schedule, event)
HTTP🌐BlueMake HTTP requests to external APIs
Set📝PurpleDefine and manipulate workflow state variables
Transform⚙️PinkTransform data using expressions or built-in operations
Switch🔀AmberConditional branching based on conditions
Loop🔄EmeraldIterate over arrays or repeat operations
Merge🔗CyanCombine multiple branches back into single flow
Wait⏱️GrayPause workflow for duration or condition
Code💻RedExecute custom JavaScript in sandboxed runtime
Database🗄️TealDatabase operations (PostgreSQL, MySQL, SQLite, MongoDB, Redis)
Email📧RoseSend emails via SMTP or monitor via IMAP
Notification🔔OrangeSend to Slack, Discord, Teams, or webhooks
RSS📡LimeMonitor RSS/Atom feeds for new entries
File📁SkyFile operations on local or cloud storage (S3, GCS, Azure)

Standard Properties

Every action node inherits these shared properties:

Identity

PropertyTypeDescription
idstringUnique identifier
namestringDisplay name
descriptionstring?Optional tooltip description

Error Handling

ModeBehavior
stopHalt workflow on error (default)
continueLog error and proceed to next node
retryRetry with configurable count (1-10) and delay (ms)
fallbackUse a fallback value on error

Tracing

PropertyTypeDescription
enabledbooleanEnable detailed execution traces
logLevelnone | error | info | debugLog verbosity

Execution Control

PropertyTypeDescription
timeoutnumberTimeout in ms (default: 30000)
conditionstring?Skip node if expression evaluates to false

Input/Output Mapping

PropertyTypeDescription
inputMappingRecord<string, string>?Map state fields to node inputs
outputKeystringKey where result is stored in workflow state

Node Reference

Trigger Node 🎯

Workflow entry point. Every workflow starts with a Trigger node. See the dedicated Triggers Guide for full details.

Trigger TypeDescription
ManualUser-initiated via chat input
WebhookHTTP endpoint (POST/GET) with optional auth
ScheduleCron-based timing with timezone support
EventExternal system events with JSONPath filtering

HTTP Node 🌐

Makes HTTP requests to external APIs with full auth, header, body, and response handling.

Configuration:

PropertyTypeDescription
methodGET, POST, PUT, PATCH, DELETEHTTP method
urlstringURL with {{variable}} interpolation
authobjectAuthentication (none, bearer, basic, api_key)
headersRecord<string, string>Request headers
bodyobjectBody (none, json, form, raw)
responseobjectResponse handling (json, text, binary) with optional JSONPath extraction
rateLimitobject?Rate limiting (requests per window)

Example:

{
  "type": "http",
  "name": "Fetch User Data",
  "method": "GET",
  "url": "https://api.example.com/users/{{userId}}",
  "auth": {
    "type": "bearer",
    "bearer": { "token": "{{API_TOKEN}}" }
  },
  "headers": { "Accept": "application/json" },
  "body": { "type": "none" },
  "response": { "type": "json", "jsonPath": "$.data" },
  "errorHandling": { "mode": "retry", "retryCount": 3, "retryDelay": 1000 },
  "mapping": { "outputKey": "userData" }
}

Set Node 📝

Defines and manipulates workflow state variables. Supports literal values, expressions, and secrets.

Configuration:

PropertyTypeDescription
modeset, merge, deleteVariable operation
variablesVariable[]List of variables to set
envVarsobject?Load from .env file with optional prefix filter

Variable types: string, number, boolean, json, expression

Variables marked isSecret: true are masked in logs and UI.

Transform Node ⚙️

Transforms data using expressions or built-in operations.

Transform types:

TypeDescription
jsonpathJSONPath expression
jmespathJMESPath expression
templateString template with interpolation
javascriptJavaScript expression

Built-in operations: pick, omit, rename, flatten, sort, unique

Type coercion targets: string, number, boolean, array, object

Switch Node 🔀

Conditional branching with multiple output ports. Each condition maps to a separate output port on the node.

Switch Properties Panel

Configuration:

PropertyTypeDescription
evaluationModefirst_match | all_matchStop at first match or evaluate all
conditionsSwitchCondition[]List of conditions with output ports
defaultBranchstring?Output port when no conditions match

Condition operators: eq, neq, gt, lt, gte, lte, contains, startsWith, endsWith, matches, in, empty, exists

Example:

{
  "type": "switch",
  "evaluationMode": "first_match",
  "conditions": [
    { "id": "ok", "name": "Success", "field": "status", "operator": "eq", "value": "success", "outputPort": "success" },
    { "id": "err", "name": "Error", "field": "status", "operator": "eq", "value": "error", "outputPort": "error" }
  ],
  "defaultBranch": "unknown"
}

Loop Node 🔄

Iterates over arrays, repeats a fixed number of times, or loops while a condition holds.

Loop types:

TypeDescription
forEachIterate over an array from state
whileLoop while condition is true
timesRepeat N times

Parallel execution: Enable parallel.enabled with optional batchSize and delayBetween for concurrent iteration.

Result aggregation: When results.collect is true, iteration results are gathered into an array under results.aggregationKey.

Merge Node 🔗

Combines multiple parallel branches back into a single flow. Has multiple input ports.

Merge modes:

ModeBehavior
wait_allWait for all incoming branches
wait_anyContinue when first branch completes
wait_nContinue after N branches complete

Combine strategies: array, object, first, last

Optional timeout with continue or error behavior.

Wait Node ⏱️

Pauses workflow execution.

Wait types:

TypeDescription
fixedWait for a fixed duration (ms, s, m, h)
untilWait until a specific timestamp
webhookWait for an incoming webhook
conditionPoll a condition at intervals

Code Node 💻

Executes custom JavaScript in a sandboxed boa_engine runtime. Graph state is injected as the global input object.

Configuration:

PropertyTypeDescription
languagejavascript, typescriptCode language
codestringCode to execute
sandboxobjectSecurity limits (network, filesystem, memory, time)

Sandbox defaults:

LimitDefault
Network accessfalse
Filesystem accessfalse
Memory limit128 MB
Time limit5000 ms

Database Node 🗄️

Performs database operations with connection pooling and parameterized queries.

Supported databases:

DatabaseDriverFeatures
PostgreSQLsqlx (postgres)Async pool, parameterized queries, row-to-JSON
MySQLsqlx (mysql)Async pool, parameterized queries, row-to-JSON
SQLitesqlx (sqlite)Async pool, parameterized queries, row-to-JSON
MongoDBmongodbNative BSON, find/insert/update/delete
RedisredisGET, SET, DEL, HGET, HSET, LPUSH, LRANGE

Connection strings are treated as secrets and masked in logs.

Email Node 📧

Send emails via SMTP or monitor incoming emails via IMAP.

Send mode (SMTP):

  • TLS/SSL support
  • Authentication
  • To/CC/BCC recipients
  • HTML or plain text body
  • {{variable}} interpolation in subject and body
  • File attachments from state

Monitor mode (IMAP):

  • Folder selection (default: INBOX)
  • Filters: sender, subject, date range, unread only
  • Mark as read after processing

Notification Node 🔔

Sends notifications to messaging platforms.

Channels: Slack, Discord, Microsoft Teams, custom webhook

Message formats: plain text, markdown, platform-specific blocks (Block Kit, Embeds, Adaptive Cards)

RSS Node 📡

Monitors RSS/Atom feeds for new entries.

  • Configurable poll interval
  • Keyword, author, category, and date filters
  • Seen-item tracking to avoid duplicates
  • Optional full content or summary only

File Node 📁

File operations on local or cloud storage.

Operations: read, write, delete, list

Cloud providers: Amazon S3, Google Cloud Storage, Azure Blob Storage

File formats: JSON, CSV, XML, text, binary (with CSV parsing options for delimiter, headers, quoting)


Variable Interpolation

All string fields in action nodes support {{variable}} syntax for dynamic values:

https://api.example.com/users/{{userId}}
Bearer {{API_TOKEN}}
Hello {{user.name}}, your order {{orderId}} is ready.

Variables are resolved from the workflow state at execution time. Dot notation (user.name) accesses nested values.

Multi-Port Nodes

Two node types have dynamic port counts:

  • Switch — one output port per condition, plus an optional default port
  • Merge — multiple input ports, one per incoming branch

These ports are visually represented on the node and connect to different downstream/upstream nodes.


Code Generation

Action nodes compile to production Rust code alongside LLM agents. Dependencies are auto-detected and added to the generated Cargo.toml.

NodeCrateWhat It Generates
HTTPreqwestAsync HTTP requests with auth, headers, body, JSONPath extraction
Databasesqlx / mongodb / redisConnection pools, parameterized queries, Redis commands
Emaillettre / imapSMTP send with TLS; IMAP monitoring with search filters
Codeboa_engineEmbedded JavaScript execution with graph state as input object
SetnativeVariable assignment (literal, expression, secret)
TransformnativeMap, filter, sort, reduce, flatten, group, pick, merge, template
MergenativeBranch combination (waitAll, waitAny, append)

All generated code uses adk-graph FunctionNode closures with GraphError::NodeExecutionFailed for error handling.

Example generated code (HTTP node):

let http_node = FunctionNode::new("fetch_data", |ctx| async move {
    let client = reqwest::Client::new();
    let resp = client.get("https://api.example.com/data")
        .bearer_auth(&ctx.get("API_TOKEN").unwrap_or_default())
        .send().await
        .map_err(|e| GraphError::NodeExecutionFailed {
            node: "fetch_data".into(),
            message: e.to_string(),
        })?;
    let body: serde_json::Value = resp.json().await?;
    Ok(NodeOutput::new().with_update("apiData", body))
});

Example generated code (Code node):

let code_node = FunctionNode::new("process", |ctx| async move {
    let mut js_ctx = boa_engine::Context::default();
    // Graph state injected as global `input` object
    // User code executed in thread-isolated sandbox
    Ok(NodeOutput::new().with_update("result", output))
});

Previous: ← Studio | Next: Triggers →