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:
| Aspect | JavaScript (Nashorn) | Python (Jython) |
|---|---|---|
| Engine | Nashorn — JS engine in the JVM | Jython — Python 2.7 inside the JVM |
| Available everywhere | Yes (default) | Yes |
| Java class access | Native — Java.type("…"), importPackage() | Native — from java.util import ArrayList |
| Returning a value | Assign to value, or last expression | scriptResult.setResult(value) |
| Modern syntax | Standard JavaScript | Python 2.7 only — no f-strings, no print() as statement |
| Third-party packages | Load JS libraries via load("…") | No pip. No pandas, no numpy, no boto3. |
| Best for | All inline logic, Java-API-heavy work | Lightweight scripts when Python syntax is preferred |
For modern Python (3.x with pip, virtual environments, full programs), don't use the inline scripting field — use the Execute Script Local or Remote via SSH flow type. That runs a real external Python interpreter and supports pandas, numpy, boto3, etc. The inline script editor is only for small things.
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:
| Location | Typical use |
|---|---|
| Mapping → field function | Calculate a destination field's value from source fields, or anonymize. |
| MAPPING → Additional Transformations → Filter | Reject rows by expression. Returns true (keep) or false (drop). |
| MAPPING → Additional Transformations → Validate | Reject rows or halt the flow with explicit TaskResult codes. |
| Before Prepare Source Query / Before Extract / For Each Row / After Extract / After Load | Five scripting transformations that run at different points of the source-to-destination pipeline. |
| Format → Preprocessor | Modify the raw source message before parsing — fix encoding, fill empty bodies, store the original. |
| Nested flow → Condition / Loop condition | Decide whether the next step runs, or how many iterations a loop performs. |
| Execute before / Execute on Exception | Setup or cleanup hooks attached to a transformation. |
| Action Conditions (database destinations) | Pick INSERT / UPDATE / DELETE / MERGE / nothing per row. |
| Execute JavaScript or Python flow | A dedicated flow type that runs only your code — no source/destination involved. |
| Dynamic SQL, function parameters, advanced config fields | Anywhere you see "Open in Editor." |
Open the editor
Wherever you see a scripting text area:
- Click Open in Editor.
- Confirm JavaScript is selected (or change to Python).
- 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:
var first = dataSet.getFieldValue(currentRow, 'first_name');
var last = dataSet.getFieldValue(currentRow, 'last_name');
value = first + ' ' + last;
The same thing in Python:
first = dataSet.getFieldValue(currentRow, 'first_name')
last = dataSet.getFieldValue(currentRow, 'last_name')
scriptResult.setResult(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:
| Language | How to return |
|---|---|
| JavaScript | Assign to value, OR rely on the last evaluated expression. |
| Python | scriptResult.setResult(the_value) — explicit, always required. |
// 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:
| Object | What it is | Available in |
|---|---|---|
etlConfig | Current flow's runtime config + key/value storage | Mapping, scripting transformations, Script flow, almost everywhere |
scenario | The flow's scenario — variables, source/destination registry | Same as etlConfig |
dataSet | The current source dataset | Mapping, For Each Row, After Extract, Filter, Validate, Action Conditions |
currentRow | The current DataSetRecord being processed | For Each Row, Mapping field functions, Filter, Validate |
row | 0-based row index (integer) | For Each Row, Filter, Validate |
fieldValue | The field value being calculated (Mapping field functions only) | Mapping field functions |
message | The raw source message (Format Preprocessor only) | Format → Preprocessor |
filter | The CSV row filter object | CSV Format → row filter |
destination | The destination context | Action Conditions |
scriptResult | Where Python writes its return value | Python scripts only |
Full availability map per location: Reference → Runtime objects.
Logging
Two ways to log from a script:
// 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.
From here: