Scripted components were the escape hatch of NiFi 1.x. When no standard processor did quite the right thing, someone dropped in an ExecuteScript, picked a language they knew, and wrote a few lines. Years later those few lines are often a few hundred, and they hold business logic nobody has documented.
NiFi 2 removes support for several of those languages in its scripting components, including ECMAScript, Lua, Ruby and the Jython-based Python engine. Groovy remains. Every script in a removed language has to be rewritten before the flow can run on NiFi 2.
Step 1: Find every script and read it
Search the flow definition for ExecuteScript, InvokeScriptedProcessor and the scripted record readers, writers, lookup services and reporting tasks. For each, record the language, whether the script is inline or loaded from a file, and the module directories it depends on.
Then read every script. That sounds slow; it is the only way to know what you are rewriting. Most fall into a few shapes:
- Attribute manipulation. Reading and setting FlowFile attributes, maybe with a date or string calculation.
- Content transformation. Reading the FlowFile content, changing it, writing it back.
- Routing. Deciding which relationship a FlowFile goes to based on its attributes or content.
- External calls. Talking to a database, an API or a file share from inside the script.
Step 2: Check whether a standard component already does it
A surprising number of scripts were written before a suitable standard processor existed, or by someone who did not know it did. Attribute manipulation is often an UpdateAttribute with expression language. Routing is often RouteOnAttribute or a record-based route. Format conversion is often a record reader and writer pair. Lookups are often a lookup service.
Replacing a script with a standard component removes code you would otherwise maintain forever, so check this first.
Step 3: Pick the rewrite target
For the scripts that remain, there are three realistic targets.
Groovy in ExecuteScript. The smallest change. The scripting API is the same, the script stays inline, and Groovy is close enough to Java that the NiFi API calls read naturally. Good for short scripts whose structure you want to keep. Less good for long scripts, because inline code is hard to test and review.
A NiFi 2 Python processor. NiFi 2 adds a native Python processor API: you write a Python class that implements a transform, package it, and NiFi runs it in a separate Python process. This is a real option when your team is stronger in Python than in Java, or when the logic relies on Python libraries. It is a different model from the old Jython engine, not a drop-in replacement: the code runs in real CPython, dependencies are declared and installed, and the processor has its own properties and relationships. Plan for packaging and dependency management, especially on air-gapped clusters where you cannot install packages from the internet.
A small Java processor. The most work up front and the easiest to test, version and maintain. Worth it for scripts on high-throughput paths, scripts with complex logic, or anything several flows depend on. Build it as a custom NAR against the NiFi 2 APIs and Java 21, with unit tests using NiFi's test runner.
A rough rule we use: short and simple becomes Groovy or a standard processor; logic that depends on Python libraries becomes a Python processor; anything on a hot path or reused widely becomes Java.
Step 4: Write the test before the rewrite
Before changing anything, capture what the existing script does with real inputs. On the 1.x cluster, route a sample of production FlowFiles through the script and save inputs and outputs, attributes included. Pay attention to edge cases: empty content, unexpected encodings, missing attributes, very large payloads.
The rewrite is done when it produces the same outputs for the same inputs, or when every difference is explained and accepted in writing.
Step 5: Watch performance
Scripts that were fine at low volume can behave differently once rewritten. A Python processor crosses a process boundary for each batch it handles, which adds overhead on very high-volume paths. A Groovy script recompiled on every change behaves differently from a cached one. Test the rewritten component at production rates before cutover, and watch the queues in front of it.
Step 6: Document the logic
The script you are replacing probably had no documentation. The replacement should: what it does, why it exists, which flows depend on it, and how to tell it is misbehaving. That page is worth more to the next engineer than the code.
Script rewrites are usually the largest variable in a NiFi 2 migration estimate, which is why our assessment reads every one.