JavaScript Node
LLMs are great at language and unreliable at arithmetic. Ask one to sum 47 invoice line items and it might round creatively, skip a row, or paraphrase your numbers. And every retry costs you another LLM call.
The JavaScript node fixes that. You write a few lines of code in the agent builder; the workflow runs them on the server, exactly, every time. Sum the items, parse a date, reshape an API response — and pass the result to the next node. No LLM involved, so it's instant, free, and gives the same answer twice.
Find it in the agent builder: open the Flow canvas, drag a connection into empty space, and pick JavaScript from the node menu.
Writing the code
Your code is the body of a function. It receives the workflow's data and must return a value:
const items = nodes.fetchOrders.response.body.items || [];
const total = items.reduce((sum, item) => sum + item.price, 0);
return { total, count: items.length, formatted: `R$ ${total.toFixed(2)}` };
Three rules:
- Always
returnsomething. The returned value is the node's output. Without areturn, the node runs and produces nothing. - Return plain data — objects, arrays, strings, numbers, booleans. Anything that fits in JSON. Functions and circular structures fail.
- Keep it synchronous. There's no
await, nofetch, no timers. To call an API, put a webhook node before this one and read its response here.
What your code can read
The function receives one object with everything the workflow knows — the same data Handlebars templates see:
| Name | What's in it |
|---|---|
vars | Workflow variables: output from earlier nodes and state fields |
input.text | The message the user sent to start this run |
nodes | Earlier node results by node id, e.g. nodes.fetchOrders.response.body |
evaluation | The most recent decision node's scores and structured data |
context | Context variables for this conversation |
env | Environment variables configured for the agent |
So vars.customerName, input.text.toUpperCase(), and nodes.fetchOrders.response.status all work the way you'd expect.
Using the result
Set the node's Output variable (say, calc) and the returned value becomes available everywhere downstream:
- In templates: an instructions node can write
The total is {{calc.formatted}} - In conditions: route the flow with a transition like vars →
calc.count→ greater than → 0 — including on the JavaScript node's own transitions, so you can branch on what the code just computed - From other code: another JavaScript node can read
nodes.<this-node-id>.result
A common pattern — validate, then branch:
const numbers = input.text.split(',').map((n) => parseFloat(n.trim())).filter((n) => !isNaN(n));
const sum = numbers.reduce((a, b) => a + b, 0);
return { sum, count: numbers.length, valid: numbers.length > 0 };
Give the node two transitions: one where calc.valid equals true goes to the answer, one where it equals false asks the user to try again.
Limits
The code runs in a sandbox with hard limits, so a typo can't take your agent down:
| Limit | Value |
|---|---|
| Time | 1 second by default; configurable up to 10 seconds |
| Memory | 64 MB |
| Returned value | 256 KB serialized |
| Network, files, imports | None — the sandbox has no fetch, no filesystem, no require |
console.log works: whatever you log shows up in the run's execution logs, which makes debugging easy.
When things go wrong
If the code throws, times out, or returns something that doesn't fit in JSON, the node records the error and the workflow keeps going through its transitions — the run doesn't crash. No output variable is written, so guard downstream conditions with an exists check when your code can fail.
Open the agent's Logs tab to see what happened: each JavaScript step shows its returned value, console output, duration, and the error message when it failed.
When to use it (and when not)
Use a JavaScript node for anything with a single correct answer: math, counting, parsing, date and currency formatting, reshaping an API response, building a string from parts.
Don't use it for:
- Understanding language — classifying intent or writing a reply is what decision and instruction nodes are for
- Calling external systems — that's the webhook node; transform its response here
- Storing a simple flag — a state node does that without any code