Scripting

Quickstart

Five minutes to know which language to pick, where you can write code, and the handful of runtime objects you'll see in every script.

Choose JavaScript or Python

Both are supported as inline scripting languages, but they have very different ceilings:

AspectJavaScript (Nashorn)Python (GraalPy)
EngineNashorn: JS engine in the JVMGraalPy: Python 3.13 inside the JVM
Available everywhereYes (default)Yes
Java class accessNative: Java.type("…"), importPackage()import java, then java.type("java.util.ArrayList")
Returning a valueAssign to value, or last expressionLast expression, or scriptResult.setResult(value)
Modern syntaxStandard JavaScriptPython 3.13: f-strings, print(), modern exception handling
Third-party packagesLoad JS libraries via load("…")No pip and no bundled pandas / numpy / boto3. The standard library is included.
Best forAll inline logic, Java-API-heavy workInline logic when Python syntax is preferred
Need pip, a virtual environment or native packages?

Embedded Python is already Python 3.13, so you do not need an external interpreter just for the language version. You do need one for packages: use the Execute Script Local or Remote via SSH flow type, which runs your own interpreter with pip, virtual environments and packages such as pandas, numpy or boto3. Choose by workload, not by Python version.

Default recommendation: JavaScript. The rest of this guide and most of the recipes use JS unless Python adds something specific.

Where you can write code

Every place Etlworks shows a scripting text area, you can drop in JavaScript or Python. Common ones:

LocationTypical use
Mapping → field functionCalculate a destination field's value from source fields, or anonymize.
MAPPING → Additional Transformations → FilterReject rows by expression. Returns true (keep) or false (drop).
MAPPING → Additional Transformations → ValidateReject rows or halt the flow with explicit TaskResult codes.
Before Prepare Source Query / Before Extract / For Each Row / After Extract / After LoadFive scripting transformations that run at different points of the source-to-destination pipeline.
Format → PreprocessorModify the raw source message before parsing: fix encoding, fill empty bodies, store the original.
Nested flow → Condition / Loop conditionDecide whether the next step runs, or how many iterations a loop performs.
Execute before / Execute on ExceptionSetup or cleanup hooks attached to a transformation.
Action Conditions (database destinations)Pick INSERT / UPDATE / DELETE / MERGE / nothing per row.
Execute JavaScript or Python flowA dedicated flow type that runs only your code, no source/destination involved.
Dynamic SQL, function parameters, advanced config fieldsAnywhere you see "Open in Editor."

Open the editor

Wherever you see a scripting text area:

  1. Click Open in Editor.
  2. Confirm JavaScript is selected (or change to Python).
  3. Write your script. The editor has syntax highlighting, indentation, and a full-screen mode.

Your first script

The simplest case: a calculated field in Mapping. Click the pen icon next to a destination field, choose Open in Editor, write:

JavaScript
var first = dataSet.getFieldValue(currentRow, 'first_name');
var last  = dataSet.getFieldValue(currentRow, 'last_name');
value = first + ' ' + last;

The same thing in Python:

Python
first = dataSet.getFieldValue(currentRow, "first_name")
last = dataSet.getFieldValue(currentRow, "last_name")
f"{first} {last}"

Both run for every row of the source dataset and write the result to the destination field. dataSet and currentRow are injected by name, no import needed.

Returning a value

How you return a result depends on the language:

LanguageHow to return
JavaScriptAssign to value, OR rely on the last evaluated expression.
PythonThe last evaluated expression, OR scriptResult.setResult(the_value). A non-null expression wins; a trailing assignment is not an expression.
JavaScript
// Both work:
value = first + ' ' + last;

// or — last expression becomes the result automatically
first + ' ' + last;

For boolean fields (Filter, Conditions, Loop conditions), return true or false. For Validate, return one of the TaskResult values (see Validate).

Runtime objects

A handful of objects are injected by name into your script. Which ones depend on where you're writing code:

ObjectWhat it isAvailable in
etlConfigCurrent flow's runtime config + key/value storageMapping, scripting transformations, Script flow, almost everywhere
scenarioThe flow's scenario: variables, source/destination registrySame as etlConfig
dataSetThe current source datasetMapping, For Each Row, After Extract, Filter, Validate, Action Conditions
currentRowThe current DataSetRecord being processedFor Each Row, Mapping field functions, Filter, Validate
row0-based row index (integer)For Each Row, Filter, Validate
fieldValueThe field value being calculated (Mapping field functions only)Mapping field functions
messageThe raw source message (Format Preprocessor only)Format → Preprocessor
filterThe CSV row filter objectCSV Format → row filter
destinationThe destination contextAction Conditions
scriptResultWhere Python writes its return valuePython scripts only

Full availability map per location: Reference → Runtime objects.

Logging

Two ways to log from a script:

JavaScript
// Add an info line to the flow log
etlConfig.log("processed " + dataSet.getRecordCount() + " rows");

// Or use the JVM logger directly
com.toolsverse.util.log.Logger.log(
  com.toolsverse.util.log.Logger.SEVERE,
  null,
  "Something went wrong"
);

Lines logged via etlConfig.log(...) appear in the flow's run log alongside platform-emitted entries: searchable from the UI and via tail-flow-log in the CLI.


You're set

From here: