Skip to main content

Script

📜

Script

Run custom Python or JavaScript in a workflow

The Script node runs a snippet of custom code as a workflow step. It supports two languages with two very different execution models: Python runs on an external Python Runner service over HTTP, while JavaScript runs in-process in a sandboxed GraalVM engine. Both receive input variables from the workflow and return a structured result, so you can drop custom logic into a job without building a separate service.

Common uses include:

  • Transforming or reshaping data that the built-in data nodes cannot express.
  • Running a small calculation or business rule inline.
  • Reading and writing spreadsheet, CSV, or JSON files as job artifacts (JavaScript).
  • Calling Python libraries for tasks the platform does not expose natively.

Before You Start​

What you may needWhere to set it upWhy it matters
Python Runner servicePlatform configurationPython scripts require a reachable Python Runner and a token. JavaScript needs neither.
Input values for the scriptGlobal VariablesPass reusable values into inputVariables instead of hard-coding them.
Files to read or produceFilesJavaScript file reads and writes flow through artifact storage (S3 / MinIO).

Actions​

ActionDescription
script:executeExecute a Python or JavaScript snippet and return its result

script:execute​

Runs the configured script in the selected language. Expressions in the source ({{ ... }}) are resolved before the code runs, so workflow values can be templated directly into the script. The script body lives under the scriptConfig root; timeouts live under executionSettings.

Parameters

ParameterLocationTypeRequiredDefaultDescription
languagescriptConfigstringNojavascriptpython or javascript
scriptscriptConfigstringYes--Source code. {{expr}} placeholders are resolved before execution
inputVariables (alias input)scriptConfigobjectNo{}Variables injected into the script scope
timeoutMinutesexecutionSettingsnumberNo10s (300s when FileIO is used)JavaScript path only. Maximum run time
timeoutSecondsexecutionSettingsnumberNo10Python path only. Clamped to 1-30 seconds

Python mode​

When language is python, the node sends the script and its input variables to the external Python Runner service over HTTP and returns the runner's response. The runner is a separate service (default :8080, path /api/v1/python/execute).

The Python path requires the runner to be configured:

  • python-runner.base-url — required. Base URL of the runner service.
  • python-runner.execute-path — required. Execution endpoint path.
  • python-runner.token — optional (empty by default). When present, the node sends it as Authorization: Bearer <token>.

If python-runner.token is absent, JavaScript steps still run normally, but a Python step throws an IllegalStateException at runtime and the step ends in FAILED.

JavaScript mode​

When language is javascript (the default), the node runs the code in-process on a sandboxed GraalVM engine. No external service or token is needed.

JavaScript scripts can read and write files through a global FileIO helper, available when the artifact client is configured (backed by S3 / MinIO). File writes are uploaded to artifact storage and returned as job-execution artifacts.

FileIO methodPurpose
readFile / writeFileRead or write raw file content
readExcel / readExcelSheet / getExcelSheetNames / createWorkbookRead Excel workbooks and sheets, or build a new workbook
readCsv / readCsvWithDelimiter / writeCsvRead CSV (optionally with a custom delimiter) and write CSV
readJson / writeJsonRead and write JSON files

Each write helper returns metadata for the produced artifact: { storagePath, fileName, mimeType, size }.

note

JavaScript runs in a GraalVM sandbox with allowAllAccess disabled. Scripts have no arbitrary host access — no filesystem, network, or process APIs beyond what the platform exposes. The only file capability available is the FileIO API described above.

Example: Transform input rows in JavaScript

FieldValue
languagejavascript
inputVariables{ "rows": [{"amount": 10}, {"amount": 20}] }
scriptconst total = rows.reduce((s, r) => s + r.amount, 0); ({ total });

What happens:

  1. The node resolves any {{ ... }} expressions in the script.
  2. It injects rows into the script scope from inputVariables.
  3. GraalVM runs the code in the sandbox and captures its return value.
  4. The result ({ total: 30 }) is returned in the result field for later steps.

Output​

JavaScript returns a structured result object:

FieldTypeDescription
resultanyThe script's return value
stdoutstringCaptured standard output
stderrstringCaptured standard error
successbooleantrue when the script completed without error
executionTimeMsintegerWall-clock run time in milliseconds
exitCodeintegerExit code of the run
errorstringError message when the script failed
artifactsarrayFiles written by FileIO, each { storagePath, fileName, mimeType, size }

Python returns the runner's raw JSON response, which uses the same field shape.

Example output (JavaScript):

{
"result": {"total": 30},
"stdout": "",
"stderr": "",
"success": true,
"executionTimeMs": 42,
"exitCode": 0,
"error": null,
"artifacts": []
}

Common Error Scenarios​

ErrorLikely CauseWhat to Check
IllegalStateException on a Python steppython-runner.token is not configuredConfigure the runner token, or switch the step to JavaScript
Python step fails to connectpython-runner.base-url / execute-path wrong or runner downConfirm the Python Runner service is reachable at the configured URL
Script timed outRun exceeded timeoutMinutes (JS) or timeoutSeconds (Python)Increase the timeout, or reduce the work the script does
ReferenceError in JavaScriptScript used a host API blocked by the sandboxUse only standard JS and the FileIO API — no filesystem, network, or process access
FileIO write failsArtifact client not configuredConfirm artifact storage (S3 / MinIO) is available for the environment
Non-zero exitCode / success: falseThe script threw an errorRead error and stderr for the failure detail

Best Practices​

  • Prefer JavaScript for file work. The FileIO helpers keep reads and writes inside artifact storage without an external service.
  • Return a value, do not print it. Downstream steps read result; use stdout only for logging.
  • Set explicit timeouts. Give long-running scripts a realistic timeoutMinutes (JS) or timeoutSeconds (Python, max 30) so they are not cut off early.
  • Keep secrets out of source. Pass credentials through inputVariables from Global Variables rather than embedding them in the script.
  • Confirm the Python Runner before shipping. A Python step fails at runtime if the runner or its token is missing, so verify the configuration in each environment.
  • Keep scripts small. Move heavy or reusable logic into a dedicated connector or service; use Script for glue and light transforms.