Your own JavaScript

The code_javascript node runs your JavaScript as a graph step. It is the last door: the thing there is no node for and no template can express.

First — do not write code

The default in Flow is a node, not code, and that is not ideology. A node is visible on the canvas, the validator sees it, its configuration lands in the run log, its failures are classified into codes, and the next person understands the graph without reading a program. Code has none of that: it is opaque to every tool the platform has, and it costs an extra credit per run.

TaskWhat to useWhere to read
Assemble a string from several valuestemplateTemplates
Parse JSON, pull out a fieldjson_parserTemplates
Branch on a conditionif / switchBranching logic
Walk a listwhile_loop / array nodesLoops
Add, count, compare numberslogic and string nodesNodes: overview
Call an external APIhttp_requestHTTP and the web
Tabular data, CSV, aggregatesdf_*Dataframes

Links for the last column: Templates, Branching logic, Loops, Nodes: overview, HTTP and the web, Dataframes.

Code earns its place where an expression stops being an expression: a non-trivial format to parse, a recursive walk over a tree, an algorithm with state and loops, stitching a dozen fields together by rules that are easier to write than to draw. The tell that it is time: a template with more than two nested conditions in it.

What arrives and what to return

You write a function body, not a file. The platform wraps it like this:

async function call(input, ...extraPorts) {
  // your code
}
  • input is the value that arrived on the Run port. A string, a number, an object — whatever the data wire delivered.
  • Every extra input port you add on the inputs tab becomes a parameter of the same name. Names are sorted alphabetically, so the order is predictable.
  • Whatever you return is the node’s output: {{ nodes.<id>.output }} is exactly the returned value. Nothing needs wrapping.
  • console.log and friends land in the node’s run log — that is the supported way to debug.
  • get_var("name") / set_var("name", value) read and write variables declared by var nodes in the same graph. An unknown name is an error, not a silent undefined (State).
Entry
JavaScript Code
Exit
  • Execute + Data
An extra input port becomes the second parameter of the function; the returned value leaves through the success output.

One more thing that reads as a bug: templates are not substituted inside the code body. A {{ secret.KEY }} written in the code stays literal text. The code field is deliberately not templated — otherwise JavaScript’s braces would need escaping, and a substituted secret would end up in the run log. If the code needs a key, add an input port and feed the value in from a separate node.

The main point: your code does not run inside the platform

Your JavaScript executes in a separate container that holds nothing but a runtime.

  1. The platform computes the whole security policy up front — allowed hosts, denied address ranges, time and memory ceilings, the code-size limit.
  2. The finished job is sent to the executor container. It decides nothing: the permission set your code runs under is handed to it, not chosen by it, and anything outside that set is rejected.
  3. Every run gets a fresh process. The result and the console.* lines stream back.

What that container has and does not have:

WhatPresent?
Platform code, its configurationno
Workspace secrets, model keysno
Access to the database, the queue, the vector storeno — it is not even on that network
Workspace files, chat attachmentsno
Write access to the filesystemno, the filesystem is read-only
Outbound networkyes, but under policy — see below
Memory and CPU ceilingsyes, the container is hard-capped

Why bother, if the code is yours anyway. Because “your code” means code you wrote and the platform executes, on machines where other customers’ data lives. One bug in a JavaScript engine is enough for a run to escape its sandbox. Had it been running inside the platform’s worker process, that escape would mean access to the database, to other people’s secrets and to other people’s files. A separate container turns the same escape into landing in a disposable empty box with no route to the database and not a single secret inside. The isolation costs us deployment complexity and costs you an administrator who has to run one more service; that is exactly why code execution does not turn on without it.

Network

fetch from code works. By default any public address is reachable; the Allowed hosts field narrows that to the hostnames you list. Private and loopback addresses are blocked always, regardless of the setting — the same guard as on http_request, and for the same reason: code that received an address from a user’s message must not become a scanner of the internal network.

Limits

What is cappedValue
Time per run5 seconds by default, ceiling 30
Memory128 MB by default, ceiling 512
Code size64 KiB
Concurrent runs per executorcapped; over capacity the node fails rather than queues

Exceeding the time budget is its own distinct failure — “the code did not finish in time”, not a generic error — so the log tells you what to fix.

Errors and billing

The error output on this node is off by default (unlike http_request): your own code failing is usually a defect to fix, not an expected outcome to handle. Turn it on with the Error output toggle in the node’s main field list (Node errors).

The sandbox’s own message is shown to the run’s author: it is their code and their bug. It is never shown to the person in the chat.

What next