The Function node runs your own code in a secure sandbox. Use it when transforms aren't enough and you need full programmatic control.
Choosing a language
When you add a Function node, pick JavaScript or Python before writing code. This choice is locked for that node — you cannot switch languages later.
Existing workflows created before multi-language support default to JavaScript when they already contain function code.
| Language | Runtime | Best for |
|---|---|---|
| JavaScript | In-process VM sandbox | Familiar syntax, async-friendly patterns |
| Python | Isolated python3 subprocess | Data processing, list/dict logic, teams that prefer Python |
Writing function code
Open the Function node and write code in the built-in editor. Click Variables to insert data references at your cursor.
JavaScript template
// Access workflow data
const inputs = {{inputs}};
const lastOutput = {{lastOutput}};
const variables = {{variables}};
const context = {{context}};
// Your custom logic here
const result = {
processed: true,
data: lastOutput,
};
return result;
Python template
# inputs, lastOutput, variables, and context are available in scope
return {
"processed": True,
"data": lastOutput,
}
Rules (both languages)
- Must return a value — the returned object becomes the node's output for downstream steps.
- Read-only scope —
inputs,lastOutput,variables, andcontextare provided for reading; mutating them won't affect other nodes. - Size limit — code must be under 10 KB.
- No network or filesystem — HTTP calls, file access, subprocesses, and environment access are blocked for security.
- 10 second timeout — long-running code is stopped automatically.
JavaScript-specific limits
require,import,fetch,process, and filesystem APIs are blocked.- Template placeholders like
{{inputs}}are replaced with actual values before your code runs.
Python-specific limits
- Runs in an isolated subprocess with restricted builtins.
- Allowed standard-library imports:
json,math,datetime,re,decimal,fractions. - Blocked:
os,sys,subprocess,socket,open(),eval(),exec(), and similar escape hatches. - Use Python dict/list syntax; returned values must be JSON-serializable.
Examples
Calculate a total (JavaScript)
const items = lastOutput.items || [];
const total = items.reduce((sum, item) => sum + (item.price || 0), 0);
return {
items,
total,
currency: variables.currency || 'USD',
};
Calculate a total (Python)
items = (lastOutput or {}).get("items") or []
total = sum((item.get("price") or 0) for item in items)
return {
"items": items,
"total": total,
"currency": (variables or {}).get("currency") or "USD",
}
Format data for an API
return {
recipient: inputs.email,
subject: `Order #${lastOutput.orderId} confirmed`,
body: `Hi ${lastOutput.customerName},\n\nYour order of $${lastOutput.amount} has been confirmed.`,
};
Parse and validate (JavaScript)
const raw = lastOutput.content || '';
let parsed;
try {
parsed = JSON.parse(raw);
} catch {
return { error: 'Invalid JSON from AI node', raw };
}
if (!parsed.email) {
return { error: 'Missing email field', parsed };
}
return { valid: true, ...parsed };
Filter and transform a list (Python)
records = (lastOutput or {}).get("data") or []
return {
"active": [r for r in records if r.get("status") == "active"],
"inactive": [r for r in records if r.get("status") != "active"],
"count": len(records),
}
Available scope
| Variable | Contents |
|---|---|
inputs | Trigger data (webhook body, manual inputs) |
lastOutput | Previous node's output |
variables | Workflow variables |
context | Outputs from completed nodes: context['node-id'].output |
Inside a Loop node, you also have access to loopItem and loopIndex.
Editor features
- Language picker — choose JavaScript or Python once when creating the node
- Syntax highlighting and line numbers for the selected language
- Expand to full-screen editor for longer scripts
- Variable inserter — click Variables to browse and insert
{{paths}}(JavaScript templates)
Error handling
If your code throws an error or has a syntax issue, the node fails and the error appears in the Execution Data tab. Common mistakes:
| Error | Fix |
|---|---|
SyntaxError | Check for missing brackets, indentation (Python), or typos |
undefined / None access | Guard with optional chaining (?.) or defaults (or {}) |
| Nothing returned | Ensure your code has a return statement |
| Code too large | Keep functions focused; split into multiple Function nodes |
| Blocked import / API | Use only allowed sandbox APIs for your language |
Function vs Transform Code
Both support JavaScript, but they serve different purposes:
| Function Node | Transform → Code | |
|---|---|---|
| Purpose | General-purpose logic | Data transformation |
| Languages | JavaScript or Python | JavaScript only |
| Output | Any shape you return | Transformed input data |
| Editor | Full code editor with expand | Inline expression in transform panel |
| Best for | Complex logic, validation, multi-step computation | Quick expressions on data shape |
| Reference | This page | Transform Catalog |
Tips
- Pick your language first — you can't change it after you start coding.
- Start with the default template and modify incrementally.
- Test with a Manual trigger and check Execution Data after each change.
- Keep functions small and focused — chain multiple Function nodes for complex pipelines.
- Use Transform → Edit Fields for simple renaming; reserve Function for real logic.