> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowx.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Supported scripts

> Scripts are used to execute actions and configure properties inside nodes. The following script languages are supported.

## Business rules scripting

> [card] [Python 3](#python-3)

> [card] [MVEL](#mvel)

> [card] [Groovy](#groovy)

> [card] [JavaScript](#javascript)

| Scripting Language | Language Version | Default Engine | Opt-in Engine |
| - | - | - | - |
| JavaScript | ECMAScript 2024 | Node.js V8 (subprocess pool) | GraalJS on GraalVM |
| Python 3 | 3.12 | CPython (subprocess pool) | GraalPy on GraalVM (Python 3.13 starting with 5.9.5) |
| MVEL | 2 | `org.mvel » mvel2` 2.5.2.Final | — |
| Groovy | 3.0.21 | `org.codehaus.groovy » groovy-jsr223` 3.0.21 | — |

> [!NOTE]
>
> **Starting with 5.9.0, JavaScript and Python execute on a native subprocess pool by default.** Existing scripts that read from `input`, write to `output`, and use language built-ins keep working. `output.put(...)`, `output.get(...)`, and bracket assignment are preserved. To keep a script on the previous GraalVM engine: business rules select the engine **per rule** — see [Script engine per rule](https://docs.flowx.ai/6.x/docs/building-blocks/actions/business-rule-action/business-rule-action.md#script-engine-per-rule) (rules created before the move to native keep GraalVM automatically); for workflow scripts, set `APPLICATION_SCRIPTENGINE_PROVIDER=graalvm` on `integration-designer`. See [Script runtime change](https://docs.flowx.ai/5.9/migrating-from-5.1-lts/api-breaking-changes.md#script-runtime-change-for-javascript-and-python-business-rules) in the 5.1 → 5.9 migration guide for the full audit.

> [!WARNING]
>
> **The GraalVM script engine is deprecated.** FlowX.AI 6.1.x is the last release family that supports GraalVM as a script engine, for every JavaScript and Python script: business rules, reusable functions, workflow Script nodes, and the rest. Move scripts that still run on GraalVM to the native engine: switch rules [per rule](https://docs.flowx.ai/6.x/docs/building-blocks/actions/business-rule-action/business-rule-action.md#script-engine-per-rule) after testing them, and remove `APPLICATION_SCRIPTENGINE_PROVIDER=graalvm` from `integration-designer` if you set it.

> [!NOTE]
>
> In version 4.7.2, we've deprecated the **DMN (Decision Model and Notation)** business rule actions. This change affects how business rules are configured on task/user task nodes in business processes.

> [!WARNING]
>
> Python 2.7 is no longer supported. Migrate Python scripts to Python 3 to take advantage of improved performance and modern language features.

## Integration designer scripting

| Scripting Language | Language Version | Default Engine | Opt-in Engine |
| - | - | - | - |
| JavaScript | ECMAScript 2024 | Node.js V8 (subprocess pool) | GraalJS on GraalVM |
| Python | 3.12 | CPython (subprocess pool) | GraalPy on GraalVM (Python 3.13 starting with 5.9.5) |

***

## Input and output

Scripts in FlowX receive data through bound variables. The available variables depend on the context.

### Available variables

| Variable | Type | Process business rules | Workflow scripts | Description |
| - | - | - | - | - |
| `input` | `Map` (read-only copy) | ✅ | ✅ | Process instance data or workflow start node data |
| `output` | `Map` (mutable) | ✅ | ✅ | Write results here — data is persisted after script execution |
| `additionalData` | `Map` | ✅ | ✅ | Contains `securityDetails` and `applicationConfiguration` |
| `instanceMetadata` | `Map` | ✅ | ❌ | Process instance identifiers — see [instanceMetadata keys](#instancemetadata-keys) (not available in workflows) |

### instanceMetadata keys

`instanceMetadata` contains only instance identifiers:

| Key | Type | Description |
| - | - | - |
| `processInstanceId` | `Number` | Internal database ID of the process instance |
| `processInstanceUuid` | `String` (UUID) | Unique identifier of the process instance |
| `parentProcessInstanceId` | `Number` | Internal ID of the parent instance (subprocesses only) |
| `parentProcessInstanceUuid` | `String` (UUID) | UUID of the parent instance (subprocesses only) |

> [!NOTE]
>
> The process definition name is **not** available in `instanceMetadata` or any other script variable. If a business rule needs the process name as data, set it explicitly — for example as a process parameter on the start node or in the start request — since the name is static per process definition.

### Writing to output

Assign values to the `output` variable to persist data. Both assignment and `.put()` syntax work.

> [tab] JavaScript
>
> ```javascript theme={"dark"}
> // Dot notation
> output.clientName = input.firstName + " " + input.lastName;
>
> // Bracket notation
> output["totalAmount"] = input.price * input.quantity;
>
> // Java method (also works)
> output.put("status", "approved");
>
> // Nested objects
> output.address = {
>   street: input.streetName,
>   city: input.cityName
> };
> ```

> [tab] Python
>
> ```python theme={"dark"}
> # Bracket notation
> output["clientName"] = input["firstName"] + " " + input["lastName"]
>
> # Java method (also works)
> output.put("totalAmount", input["price"] * input["quantity"])
>
> # Nested objects
> output["address"] = {
>   "street": input["streetName"],
>   "city": input["cityName"]
> }
> ```

### How output is merged into process data

In process business rules, `output` starts empty every time the script runs. When the script finishes, FlowX merges `output` into the existing process data instead of replacing it. Keys you don't write to keep their current values.

The merge works key by key:

| What you write | Existing value | Result |
| - | - | - |
| An object, for example `output.client = { city: "Cluj" }` | An object | Merged recursively: `client.city` is updated, all other keys under `client` are kept |
| An object | Missing, or not an object | The object is stored as the new value |
| A string, number, or boolean | Anything | The new value replaces the existing one |
| An array, for example `output.items = [...]` | Anything | The whole array is replaced. Arrays are never merged item by item |
| `null` (`None` in Python) | Anything | The value is set to `null`. The key stays in the process data |
| An empty object, `{}` | An object | No change: the existing object and its keys are kept |

To update one item in an array, read the array from `input`, change it, and write the full array back to `output`.

> [!WARNING]
>
> Writing `{}` doesn't clear an object that already exists in the process data. To clear it, set the key to `null`. To clear a single nested key, set only that key to `null`, for example `output.client = { city: null }`.
>
> `delete output.key` only removes a key you wrote earlier in the same script. It can't remove data the process instance already holds.

### Reading from input

`input` is a deep copy of the process or workflow data. Changes to `input` are not persisted. Always write to `output`.

> [tab] JavaScript
>
> ```javascript theme={"dark"}
> // Dot notation
> var name = input.application.client.name;
>
> // Bracket notation
> var code = input["application"]["countryCode"];
>
> // Safe access for optional fields
> var detail = input.query?.detail_level || "basic";
> ```

> [tab] Python
>
> ```python theme={"dark"}
> # Bracket notation
> name = input["application"]["client"]["name"]
>
> # Check before accessing optional fields
> if "countryCode" in input["application"]:
>     code = input["application"]["countryCode"]
> ```

### Accessing configuration parameters

Retrieve project-level configuration parameters through `additionalData`:

```javascript theme={"dark"}
var commission = additionalData.applicationConfiguration.get("commissionPercentage");
output.commissionValue = input.amount * commission;
```

For security details and more examples, see [Extracting additional data in business rules](https://docs.flowx.ai/6.x/docs/building-blocks/actions/business-rule-action/extracting-additional-data.md).

### Common pitfalls

> [accordion] Output is empty (\{})
>
> If your script runs without errors but output is `{}`:
>
> * **Check your variable names**. `output` must be spelled exactly, it's case-sensitive
> * **Check assignment syntax**. In Python on the GraalVM engine, use `output["key"] = value` (bracket notation), not `output.key = value`. The default native engine accepts both forms
> * **Don't reassign output**. On the GraalVM engine, `output = {"key": "value"}` replaces the reference and is lost, because the engine reads back its own `output` object. The default native engine keeps the reassigned object, but `output["key"] = "value"` works on both engines, so use bracket assignment
> * **Don't use `return`**. Scripts don't need a return statement. Write directly to `output`.

> [accordion] Same JavaScript rule, different output on native and GraalVM
>
> The native and GraalVM engines don't always produce the same output for the same JavaScript script. Test each rule on the engine it runs on, and test it again after you switch its engine.
>
> The engines differ when a script assigns `undefined` to a key of `output`, at any nesting level:
>
> * **Native** leaves the key out of the output, so the process data keeps its current value.
> * **GraalVM** writes the key as `null`, so the current value is cleared.
>
> For how each value is applied, see [How output is merged into process data](#how-output-is-merged-into-process-data).
>
> Example, with this process data before the rule runs:
>
> ```json theme={"dark"}
> {
>   "topics": { "asd": "topic" },
>   "nested": { "a": "old", "b": 0 },
>   "arr": ["old"],
>   "other": { "keep": 1 }
> }
> ```
>
> | Script | Result on GraalVM | Result on native |
> | - | - | - |
> | `var dm = JSON.parse("{}"); output.topics = dm.topics;` | `"topics": null` (cleared) | `"topics": {"asd": "topic"}` (kept) |
> | `output.nested = {a: undefined, b: 1};` | `"nested": {"a": null, "b": 1}` | `"nested": {"a": "old", "b": 1}` |
> | `output.arr = [undefined, 2];` | `"arr": [null, 2]` | `"arr": [null, 2]` |
> | `output.other = null;` | `"other": null` | `"other": null` |
>
> Only the first two scripts differ. An `undefined` array item becomes `null` on both engines, and an explicit `null` clears the value on both.
>
> To get the same result on both engines, make the intent explicit instead of relying on `undefined`:
>
> ```javascript theme={"dark"}
> var source = input.application || {};
>
> // Clear the value when the source is missing
> output.topics = source.topics ?? null;
>
> // Or keep the current value when the source is missing
> if (source.topics !== undefined) {
>   output.topics = source.topics;
> }
> ```
>
> Workflow Script nodes behave the same way. A workflow script runs on GraalVM only when `APPLICATION_SCRIPTENGINE_PROVIDER=graalvm` is set on `integration-designer`. In that case a key set to `undefined` is written as `null`, which clears the value that earlier nodes put in the workflow data. On the default native engine, the value is kept.
>
> Python scripts aren't affected: `None` is written as `null` on both engines.

> [accordion] Python import errors
>
> On the GraalVM engine (GraalPy), Python scripts run in a sandboxed environment. Standard library modules such as `uuid`, `re`, `hashlib`, `hmac`, `secrets`, and `base64` can be imported. The modules that aren't available are listed under [Python Library Support](#python-library-support).
>
> On the default native engine (CPython), standard library modules such as `uuid`, `re`, `hashlib`, `hmac`, `secrets`, and `base64` can be imported. Modules that reach the system, network, or files, or that inspect or generate code, are blocked together with their submodules, and fail with `Import of '<module>' is not allowed in FlowX scripts`. The blocked modules are `os`, `sys`, `subprocess`, `multiprocessing`, `signal`, `ctypes`, `shutil`, `pathlib`, `glob`, `tempfile`, `io`, `socket`, `ssl`, `select`, `selectors`, `asyncio`, `http`, `urllib`, `ftplib`, `smtplib`, `xmlrpc`, `requests`, `httplib2`, `aiohttp`, `httpx`, `webbrowser`, `antigravity`, `turtle`, `tkinter`, `inspect`, `dis`, `code`, `codeop`, `compileall`, `importlib`, `pkgutil`, `modulefinder`, `types`, `pickle`, `shelve`, and `marshal`.
>
> ```python theme={"dark"}
> # ✅ Works on both engines
> import uuid
> output["id"] = str(uuid.uuid4())
>
> # ❌ Fails on the native engine: Import of 'os' is not allowed in FlowX scripts
> import os
> ```

> [accordion] Python built-ins such as print aren't available
>
> On the default native engine, these Python built-ins are removed: `print`, `input`, `open`, `exec`, `eval`, `compile`, `getattr`, `setattr`, `delattr`, `globals`, `locals`, `vars`, `dir`, `memoryview`, `bytearray`, `exit`, `quit`, and `breakpoint`. A script that calls one fails with `NameError`, for example `NameError: name 'print' is not defined`.
>
> To inspect a value while you build a script, write it to `output` instead of printing it, and remove the key once the script works, because `output` is saved to the process data:
>
> ```python theme={"dark"}
> # ❌ Fails on the native engine: NameError: name 'print' is not defined
> print(input["amount"])
>
> # ✅ Works on both engines
> output["debugAmount"] = input["amount"]
> ```

> [accordion] Python syntax limitations
>
> Some Python patterns behave differently in the GraalPy sandbox:
>
> ```python theme={"dark"}
> # ❌ enumerate() not available
> for i, item in enumerate(items):
>
> # ✅ Use manual index
> i = 0
> while i < len(items):
>     item = items[i]
>     i = i + 1
>
> # ❌ .get() with default argument may cause arity errors
> value = input.get("key", "default")
>
> # ✅ Check key existence first
> if "key" in input:
>     value = input["key"]
> else:
>     value = "default"
>
> # ❌ dict.items() iteration not supported
> for k, v in data.items():
>
> # ✅ Iterate over keys
> keys = list(data.keys())
> i = 0
> while i < len(keys):
>     k = keys[i]
>     v = data[k]
>     i = i + 1
> ```

> [accordion] Java HashMap interop in JavaScript
>
> When accessing data returned by Java services (such as AI node output), values may be Java HashMaps rather than native JavaScript objects. Standard JS methods like `Object.keys()` and spread syntax may not work as expected.
>
> ```javascript theme={"dark"}
> // ❌ May not work with Java HashMaps
> var keys = Object.keys(javaMap);
> var copy = {...javaMap};
>
> // ✅ Use Java interop
> var value = javaMap.get("key");
> javaMap.put("key", "value");
> ```

> [accordion] Can I use the Node.js crypto module in JavaScript?
>
> No. JavaScript scripts don't run as Node.js modules, so `require` doesn't exist and Node.js modules such as `crypto`, `fs`, or `http` can't be loaded. Calling `require('crypto')` fails with `ReferenceError: require is not defined`. There is no `crypto` global either.
>
> On the default native engine, a script sees only the standard JavaScript built-ins (`JSON`, `Math`, `Date`, `RegExp`, and similar) plus the script variables such as `input` and `output`. Node.js globals such as `process` and `Buffer` aren't available.
>
> To hash data or generate IDs, use a Python script, where `hashlib`, `hmac`, `secrets`, and `uuid` can be imported on both engines:
>
> ```python theme={"dark"}
> import hashlib
> import uuid
>
> output["checksum"] = hashlib.sha256(input["payload"].encode()).hexdigest()
> output["id"] = str(uuid.uuid4())
> ```

> [accordion] console.log prints nothing
>
> On the default native engine, `console.log`, `console.info`, `console.warn`, and `console.error` exist, so calling them doesn't fail, but they discard what you pass them and nothing reaches the service logs. To inspect a value while you build a script, write it to `output`, for example `output.debugAmount = input.amount;`, and remove the key once the script works.

### Scripts in Integration Workflows

Script nodes in [Integration Workflows](https://docs.flowx.ai/6.x/docs/platform-deep-dive/integrations/integration-designer.md) use the same `input` and `output` variables as process business rules, but the data flow is different:

* **In a process business rule**, `output` writes directly to the process instance data store.
* **In a workflow Script node**, FlowX merges `output` into the workflow data, which is the `input` for the **next node** in the workflow. The data stays within the workflow until the workflow completes at an **End** node.

Only the End node output is mapped back to the calling process (via a Receive Message Task with a **Workflow** data stream).

> [!NOTE]
>
> FlowX merges a workflow Script node's `output` into the workflow data. Keys the script doesn't write keep their values, so later nodes still read data from earlier nodes, and an empty `output` (`{}`) changes nothing, as in process business rules. Write only the keys you add or change.

For details on mapping workflow output back to your process, see [Workflow data models](https://docs.flowx.ai/6.x/docs/platform-deep-dive/integrations/workflow-data-models.md).

***

## JavaScript

JavaScript scripts run on one of two engines:

| Engine | Runtime | When it's used |
| - | - | - |
| Native (default) | Node.js V8, in a subprocess pool | Default for new business rules and for workflow scripts |
| GraalVM (opt-in) | GraalJS | Business rules set to GraalVM, including rules created before the move to native, and workflow scripts when `APPLICATION_SCRIPTENGINE_PROVIDER=graalvm` is set on `integration-designer` |

Business rules select the engine per rule. See [Script engine per rule](https://docs.flowx.ai/6.x/docs/building-blocks/actions/business-rule-action/business-rule-action.md#script-engine-per-rule).

### Native engine (default)

Scripts run in an isolated V8 context. A script sees the standard JavaScript built-ins (`JSON`, `Math`, `Date`, `RegExp`, and similar) plus the script variables such as `input` and `output`. `require`, Node.js modules such as `crypto` or `fs`, and Node.js globals such as `process` and `Buffer` aren't available. `console.log` and the other `console` methods write nothing.

### GraalVM engine (opt-in)

> [!NOTE]
>
> **New in v4.7.1**: JavaScript support has been upgraded from Nashorn (ECMAScript 5.1) to GraalJS (ECMAScript 15/2024), providing significantly improved performance and modern language features.

On the GraalVM engine, JavaScript is powered by GraalJS, which supports ECMAScript 15 (2024) standards. This provides modern JavaScript capabilities for your business rules and integrations.

#### What is GraalJS?

GraalJS is an ECMAScript compliant JavaScript implementation built on GraalVM. It supports the latest ECMAScript features and offers high performance through the GraalVM's JIT compiler.

#### Properties

* Supports ECMAScript 15 (2024) features including modern syntax and APIs
* Provides consistent scripting across business rules and integration designer
* Runs in a secure sandboxed environment

#### Limitations

On the GraalVM engine, JavaScript scripts run in a sandboxed environment. Here is a list of JavaScript features not available in the sandbox:

* import.meta (ES2020)
* top-level await (ES2022)
* set operations (ES2024)
* Array.fromAsync (ES2024)

### Useful links

> [card] [GraalJS Documentation](https://www.graalvm.org/javascript/)

> [card] [ECMAScript 2024 Language Specification](https://tc39.es/ecma262/)

***

## Python 3

Python is a high-level, interpreted programming language known for its simplicity and readability. FlowX.AI runs Python scripts on one of two engines, selected the same way as for [JavaScript](#javascript): per business rule, and for workflow scripts through `APPLICATION_SCRIPTENGINE_PROVIDER` on `integration-designer`.

| Engine | Runtime | Python version |
| - | - | - |
| Native (default) | CPython, in a subprocess pool | 3.12 |
| GraalVM (opt-in) | GraalPy | 3.12 in 5.9.0 to 5.9.4, 3.13 starting with 5.9.5 |

### Native engine (default)

Standard library modules such as `uuid`, `re`, `hashlib`, `hmac`, `secrets`, and `base64` can be imported. Modules that reach the system, network, or files, such as `os`, `subprocess`, `socket`, `urllib`, and `io`, are blocked and fail with `Import of '<module>' is not allowed in FlowX scripts`. Built-ins such as `print`, `open`, `eval`, `exec`, and `getattr` are removed. See [Common pitfalls](#common-pitfalls) for the full lists.

Both `output["key"] = value` and `output.key = value` write to `output`.

### GraalVM engine (opt-in)

#### What is GraalPy?

GraalPy is an implementation of Python that runs on the GraalVM. It offers high compatibility with standard Python (CPython) while providing the ability to run within the Java ecosystem. GraalPy supports Python 3 and provides access to a large subset of the standard Python library.

#### Properties

* Supports Python 3.12 (Python 3.13 starting with 5.9.5) with access to most common Python libraries
* Runs up to 3x faster than Python 2.7 via Jython
* Runs in a sandboxed environment for better security

#### Python Library Support

On the GraalVM engine, Python 3 support in FlowX comes with a subset of the [standard Python library](https://docs.python.org/3.12/library/index.html). Python runs in a sandboxed environment and the following modules are not available:

"stringprep", "sqlite3", "plistlib", "getpass", "curses", "curses.textpad", "curses.ascii", "curses.panel", "xml.parsers.expat", "xmlrpc.client", "xmlrpc.server", "turtle", "tkinter", "test.support", "symtable", "pyclbr", "msvcrt", "winreg", "winsound", "grp", "termios", "tty", "pty", "syslog", "audioop", "msilib", "nis", "ossaudiodev", "smtpd", "spwd", "crypt"

> [!WARNING]
>
> Available modules might provide limited access to system resources due to the execution in a sandbox environment.

### Useful links

> [card] [Python 3.12 Documentation](https://docs.python.org/3.12/)

> [card] [GraalPy Documentation](https://www.graalvm.org/python/)

## MVEL

MVEL is an expression language for Java-based applications. It provides a plethora of features and is suited for everything from the smallest property binding and extraction, to full-blown scripts.

* FlowX.AI uses [**mvel2 - 2.5.2.Final version**](https://mvnrepository.com/artifact/org.mvel/mvel2/2.5.2.Final)

### Useful links

> [card] [MVEL Documentation](http://mvel.documentnode.com/)

> [card] [Maven repository: Mvel 2.5.2 Final](https://github.com/mvel/mvel/tags)

***

## Groovy

Groovy is a multi-faceted language for the Java platform. The language can be used to combine Java modules, extend existing Java applications and write new applications

We use and recommend **Groovy 3.0.21** version, using **groovy-jsr223** engine.

> [!NOTE]
>
> **Groovy** has multiple ways of integrating with Java, some of which provide richer options than available with **JSR-223** (e.g. greater configurability and more security control). **JSR-223** is recommended when you need to keep the choice of language used flexible and you don't require integration mechanisms not supported by **JSR-223**.

> [!NOTE]
>
> **JSR-223** (spec) is **a standard scripting API for Java Virtual Machine (JVM) languages** . The JVM languages provide varying levels of support for the JSR-223 API and interoperability with the Java runtime.

### Useful links

> [card] [Groovy Language Documentation](https://docs.groovy-lang.org/docs/groovy-3.0.21/html/documentation/)

> [card] [\[Java\] Class GroovyScriptEngineImpl](https://docs.groovy-lang.org/latest/html/gapi/org/codehaus/groovy/jsr223/GroovyScriptEngineImpl.html)

> [card] [groovy-jsr223](https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-jsr223)

***

## Academy courses

> [card] [Exclusive Gateways course](https://academy.flowx.ai/explore/configure-exclusive-gateways)
>
> Learn to configure conditions in JavaScript and DMN for gateway routing

> [card] [Debug 101 course](https://academy.flowx.ai/explore/debug-your-process-0)
>
> Troubleshoot script execution errors, exceptions, and debugging patterns

> [!TIP]
>
> **Academy playground**. Explore the [**Academy\_ExclusiveGateways**](https://designer-workshop-51x.playground.flowxai.dev/workspace/00000000-0000-0000-0000-000000000001/projects/173d95f6-a1ee-447a-853c-3edee11b75b1/config/2a6fc79d-f993-4114-94d8-771104ffb650/processes) project for working examples of JavaScript and DMN conditions in gateway routing.


## Related topics

- [Node actions](https://docs.flowx.ai/6.x/docs/building-blocks/actions/actions.md)
- [Business rules types](https://docs.flowx.ai/6.x/docs/building-blocks/actions/business-rule-action/business-rule-action.md)
- [FlowX.AI 6.0.0 Release Notes](https://docs.flowx.ai/release-notes/v6.x/v6.0.0-october-2026/v6.0.0-october-2026.md)
- [Adding an action to a node](https://docs.flowx.ai/6.x/docs/flowx-designer/managing-a-project-flow/adding-an-action-to-a-node.md)
- [Service Task node](https://docs.flowx.ai/6.x/docs/building-blocks/node/task-node.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.