Groovy scripted processors and record transforms in NiFi

Scripts in NiFi can cover small transformations quickly, but they carry testing, performance and upgrade costs that grow with the flow. This page helps you decide when a script is enough and when a real processor is the better choice.

On this page

When a Groovy script in NiFi is the right tool

A Groovy script is the right tool when the transform is specific to one flow, changes often, and does not need to be shared across many flows or tested like a product. A compiled processor is the better choice when the logic is reused, needs its own versioned release, or must run under the same review and testing as the rest of your code. In NiFi, this decision starts with three components: ExecuteGroovyScript, which runs a script against FlowFiles, ScriptedTransformRecord, which runs a script against each record in a record-oriented flow, and InvokeScriptedProcessor, which wraps a full scripted processor you write yourself. This page covers when each one fits, what they cost in throughput and maintenance, and how they behave under restricted component policies and across upgrades.

This section sets the boundary for the rest of the page. Scripts are a practical option for one-off routing, field mapping and record filtering, but they inherit the NiFi runtime, the script engine and the policies your administrators set, so their risks are different from those of a compiled NAR. Apache NiFi is released under the Apache License 2.0 (SPDX: Apache-2.0), and the project itself offers no paid edition. The decision about scripts versus processors is therefore about your engineering practice, not licensing. Pages on writing custom processors, controller services and NAR packaging cover the compiled path in depth and are the natural next read once you have decided a script is not enough.

DeployOpen plans and builds these flows inside your own infrastructure, including the NiFi nodes, the script engine configuration and the test harness, so that the choice between script and processor is made against your real volumes, change process and security policy. Before committing, confirm which NiFi line you run, because script engine availability and component names differ between 1.x and 2.x, and ask whether your administrators allow scripted components under your restricted component policy. The sections that follow give the decision criteria and the checks to run before a script goes into production.

What the scripted components do

NiFi ships three ways to run a script inside a flow: ExecuteGroovyScript, ScriptedTransformRecord and InvokeScriptedProcessor. Each one hands control of FlowFile handling to code you maintain, so the choice between them, and the decision to use a compiled processor instead, shapes testing, performance and upgrade effort.

ExecuteGroovyScript

ExecuteGroovyScript runs an inline or referenced Groovy script against each FlowFile and is the quickest way to prototype a transformation or routing rule. The script body lives in the processor configuration, so it is visible to anyone who can edit the flow and is reviewed as configuration rather than code. Check where the script comes from, how it is versioned, and whether its logic can be unit tested outside the flow before it reaches production.

ScriptedTransformRecord

ScriptedTransformRecord evaluates a script against each record to transform, filter or fork records. Because it works on record-oriented content, it fits schema-aware pipelines where the same logic must run over thousands of rows in one FlowFile. Confirm in the NiFi 2 component documentation which record reader and writer settings, and which script engine behavior, apply to your version before you rely on them.

InvokeScriptedProcessor

InvokeScriptedProcessor loads a script as a processor implementation, so the script defines the processor's lifecycle, properties and relationships. It sits between a one-off script and a compiled extension, and it is the component most likely to need rework when NiFi changes its processor APIs. Ask who owns the script file, where it is stored on each cluster node, and how a change is rolled out to every node.

Script access to the NiFi API

Scripts run with access to the FlowFile, its attributes and content, and the processor context, so they can read and change what the component exposes to them. Access to the wider NiFi API, controller services and session behavior depends on the component and the script engine bindings. Treat every script as code with the reach of its processor, document which bindings each script uses, and confirm the exposed objects in the NiFi 2 docs for your release.

Restricted component policy

Scripted components are restricted in NiFi because they can execute arbitrary code, so access to them is governed by the restricted component policy and by who holds the matching permissions. Administrators should decide which users may create or edit scripts, and record that decision in the authorization policy. Confirm how your NiFi release enforces this policy for each scripted component before granting it to a wider group.

Upgrade exposure

Scripts depend on processor APIs, bindings and engine behavior that can change between NiFi releases, and NiFi 2 changed several extension and configuration details. Scripts are not covered by a version check at build time, so a flow that runs on 1.x can fail or behave differently after migration. Inventory every scripted component before an upgrade, and confirm version-specific behavior in the NiFi 2 component docs and migration guidance.

Script, scripted record transform or real processor

This table compares the three scripted options (ExecuteGroovyScript, ScriptedTransformRecord and InvokeScriptedProcessor) with a custom processor packaged as a NAR across the factors that decide the choice. Read each row against your own flow: the right option depends on how much logic you have, how often it changes and who will test and maintain it. For many one-off or record-level tasks a script is enough, but shared clients, heavy logic and long-lived code usually belong in a compiled extension.

FactorScripted componentsCustom NAR processor
Record-level transformsScriptedTransformRecord suits field mapping, filtering and forking across records using the record API, without a build stepPossible, but more code to write for simple field changes that a script or built-in record processor handles
Per-FlowFile logicExecuteGroovyScript and InvokeScriptedProcessor fit short, mostly stateless logic on each FlowFileBetter for complex branching, large libraries or logic that must be reviewed and versioned as code
Shared clients and connectionsScripts are poorly suited to pooled connections, since each script instance manages its own resourcesConnection pools and clients belong in a controller service, shared across processors
TestingTesting relies on scripts run through NiFi or ad hoc harnesses, which is harder to automate in CIUnit tests with the nifi-mock TestRunner can run in a standard build pipeline
PerformanceInterpreted scripts add overhead per FlowFile or record, which matters at high volume; measure on your own flowCompiled code avoids script interpretation overhead and is easier to profile
Restricted component policyScripting components are restricted and need explicit authorization, so review who may add or edit themUses the same restricted policy only if it needs unusual capabilities; confirm your policy model with your security team
Upgrade riskScripts can break when NiFi APIs or script bindings change between major versions; confirm impact in migration guidanceRecompiling against new NiFi APIs is still required, but changes are visible in version control and build output
Ownership and change controlScripts often live in flow definitions, which makes review and rollback harderCode lives in a repository with normal review, tagging and deployment steps

How a scripted component moves from prototype to production

This sequence turns a quick Groovy script into a component your team can test, govern and promote with confidence. Each step produces a record that shows whether the script should stay a script or become a processor.

  1. Define the transform contract and record schema

    Write down what the component receives, what it must emit and which records it filters or forks. Name the input and output record schemas, the fields it reads and writes, how it treats nulls and type mismatches, and which failures route to failure or are dropped. Involve the data owner and the team that consumes the output. The step is done when the contract is a short document both teams have approved, with sample input and expected output records attached.

  2. Prototype the transform in a script

    Build the first version in ExecuteGroovyScript, ScriptedTransformRecord or InvokeScriptedProcessor, depending on whether the logic works per record or per FlowFile. Keep the prototype on a non-production NiFi instance and avoid hard-coded credentials, hosts or paths by using parameters. The step is done when the script runs end to end against the sample records from the contract and the team can explain every branch it takes.

  3. Measure throughput and error paths with representative data

    Run the prototype against a data set that matches production volume, record size, schema variety and malformed input. Record throughput, latency, heap and garbage collection behavior, and how many FlowFiles reach failure. Inspect provenance for the error cases. The step produces a measurement record that states the test data, the flow configuration and the observed results. If the numbers do not meet the requirements agreed in the contract, the decision in the next step should lean toward a compiled processor.

  4. Decide between script and processor

    Compare the measurements and the contract against the factors that favor each option: sustained per-record cost, the need for shared controller services, the number of flows that reuse the logic, the expected rate of change and who will maintain it. Record the decision and its reasons in the component's design note. Confirm with the NiFi administrator whether scripting is permitted by the restricted component policy in your environment. The step is done when the decision is signed off, and if the answer is a processor, the script becomes the reference specification for that build.

  5. Add automated tests for the component

    Create tests that cover the contract's valid records, filtered records, forked records, malformed input and failure routing. For a script, this usually means exercising the script with a test harness outside production and keeping the inputs and expected outputs in version control. For a processor, use the nifi-mock TestRunner in the build. Run the suite in CI on every change. The step produces a test suite and a recorded result set showing that every contract case passes, with the commit identifier attached.

  6. Configure restricted component policy and change control

    Work with the NiFi administrator to define who may create or edit scripted components, which scripting components are permitted in each environment and how authorization policies are applied to them. Store the script or processor source in the flow's versioned repository so each change has an author, a reviewer and a history. Confirm the approach against your own change management procedure. The step is done when the policy, the approvers and the version control location are documented and tested with a non-privileged user account.

  7. Promote through environments with a promotion record

    Deploy the approved version to a staging cluster using the same flow version and parameter values that production will use, then run the measurement and test suites again. After approval, promote to production through your normal change window. Keep a promotion record listing the version, the environment, the parameter set, the test results and the approver. Ask the NiFi vendor or your support provider which upgrade path affects the chosen component type before the next NiFi upgrade. The step is complete when production runs the approved version and the promotion record is filed.

Performance and testing trade-offs in scripted flows

Scripts in a hot path cost more than their line count suggests. ExecuteGroovyScript, InvokeScriptedProcessor and ScriptedTransformRecord run your code once per FlowFile or once per record, so any work that happens inside the script repeats at that rate. Creating a parser, compiling a regular expression, opening a connection or building a large map inside the script body is paid on every invocation unless you move it into a field initialized once or into a controller service. Per-FlowFile state held in script variables also deserves scrutiny: values that outlive a single invocation can grow without bound, and a script that reads whole content into a String or a parsed tree holds that memory for the length of the call. In ScriptedTransformRecord, inline parsing of record content inside the script is a common source of heap pressure, because the script handles data the record reader has already decoded. Measure before you tune. Run the same flow volume with the script and with the candidate replacement, and capture throughput, heap use, garbage collection pauses and queue back pressure in your own cluster, using the metrics your operations team already collects. Confirm the actual numbers with your own data shapes, since record size and content variety change the result far more than the script syntax does.

Testing a script is different from testing a compiled processor. A compiled processor built on the NiFi API is packaged as a NAR, has typed properties and relationships, and can be exercised through the mock framework in an ordinary build. A script is loaded by the scripting engine at runtime, so compile errors, missing imports and wrong property names often surface only when the processor starts in a running flow. Plan a harness that loads the script file, supplies a fake session and FlowFiles with representative attributes and content, and asserts on relationships and output. Confirm with your team whether the scripting bundle you deploy can be exercised outside a running NiFi instance, and which Groovy and NiFi API versions your scripts must match. For the full approach to unit testing compiled components, see the sibling topic on testing custom NiFi processors with nifi-mock, which covers the TestRunner workflow in CI. Scripts also need an explicit decision on who reviews changes, because a one-line edit in the UI can alter production behavior without passing through your build pipeline.

What drives the cost of scripted components

This table lists the factors that change the effort of a Groovy scripted component, how to keep each one down, and what to request in a fixed-scope quote. Read it before scoping, because most of the variance comes from the number of scripts, external calls and upgrade exposure rather than from the script logic itself.

DriverWhy it changes effortHow to keep it downAsk for in the quote
Number of transformsEach ScriptedTransformRecord or ExecuteGroovyScript instance carries its own script, properties and tests, so effort grows with every separate transform.Merge related logic into one script with clear branches, or move shared logic into a common library used by several flows.A list of each transform with its inputs, outputs and the flow it belongs to.
Record schema complexityNested records, unions, optional fields and schema changes make scripts harder to write and to prove correct against sample data.Fix the input and output schemas early, and prefer flat or well-defined record shapes where the source allows it.Named schemas, sample files for each schema version, and the expected handling of missing or null fields.
External callsLookups to databases, APIs or caches add connection handling, timeouts, retries and failure tests that a pure transform does not need.Route external access through a shared controller service and cache results where the data allows it.The list of external systems, their authentication method, and whether mocks or test endpoints are provided.
Test coverage expectedUnit tests for each branch, error path and schema variant take more time than the script itself, and the level of evidence varies by client.Agree a test matrix before build, covering happy path, malformed input and each routing outcome.Test cases, the test harness to be used, and whether tests must run in the client's CI pipeline.
Restricted component policy reviewScripted components run arbitrary code, so the client's policy on who may add or change them adds review and approval steps.Confirm the policy early and keep scripts within allowed components so reviews are scoped to known code.Who approves script changes, the review steps, and the evidence the client needs to record for each approval.
Upgrade readiness of script APIsScripts that depend on internal NiFi classes or deprecated APIs need rework during NiFi 2 migration, and that rework recurs at each upgrade.Use documented APIs and record-based processors, and check the NiFi 2 migration guidance before writing new scripts.A statement of which NiFi version is targeted, and a plan for re-testing scripts after each upgrade.
Number of environmentsEach environment needs its own properties, credentials, parameter values and test runs, and drift between them creates rework.Use parameters and parameter contexts for environment values so the script code stays identical across stages.The number of environments, who deploys to each, and whether flow versions are promoted through a Git-based registry.
Handover and runbooksScripts maintained by people who did not write them need documentation of inputs, outputs and failure behavior, which adds time at delivery.Keep script headers and property descriptions current during build rather than at the end.Documentation deliverables, the handover session, and the support period included in the fixed scope.

How scripted components affect NiFi upgrades

Do Groovy scripts in NiFi break when upgrading from 1.x to 2.x?

They can. Scripts are not re-checked by the upgrade tooling in the same way as processor properties, so a script that calls an API, property or service name that changed in NiFi 2.0 can fail only when it runs. The risk sits in the code itself, which is why each script needs to be inventoried and tested against the target version before cutover. Treat every ExecuteGroovyScript, ScriptedTransformRecord and InvokeScriptedProcessor instance as a dependency that needs an owner and a test case.

What is the required path from NiFi 1.x to NiFi 2.x?

The migration guidance requires upgrading to NiFi 1.27.0 before moving to 2.0.0. Skipping that step is not supported, so a 1.x cluster on an older release needs a staged path. The guidance also requires changing the flow configuration file from flow.xml.gz to flow.json.gz. Plan the upgrade as two moves: first to 1.27.0 with the flows running and verified, then to 2.x with the flow format change and script review applied. Confirm the exact steps for your current release in the migration guidance before you schedule the work.

How does the variable registry change affect scripts in NiFi 2?

In NiFi 2.0 the variable registry expression language scope was removed and replaced by an ENVIRONMENT scope. Any script that reads or relies on variable registry values, directly or through expression language used in its properties, needs to be reviewed for the new scope. Scripts often hold configuration values in code or pull them from attributes, so the review should cover hardcoded values, property names and any lookups that assume the old scope. Confirm the scoping rules with the migration guidance and test each affected flow with the same parameter and variable setup used in production.

Which renamed components could break scripted flows?

The migration guidance states that the distributed map cache components were renamed in NiFi 2.0. A script that references a cache client or server by its old class name, or that depends on a property name that changed, will not work after the upgrade. Inventory every script for references to cache, service and processor names, and check whether any script configures components dynamically at runtime. Flows that load components by name are the hardest to spot in a review, so search the script source as well as the flow definition.

What should I inventory before upgrading NiFi with scripted components?

Start with a complete list of every scripted component across all process groups, including those in disabled or rarely used flows. For each one, record the processor type, the script source or file location, the language version, the external libraries it imports, the controller services and caches it uses, and the variables and parameters it reads. Add the owner, the business function and the last time the script changed. Also note which scripts run on a schedule or only in a failure path, because those are easy to miss in a smoke test.

Can I test scripted components before a NiFi upgrade?

Yes, and the test should run on a copy of the production flow definition in a non-production environment that uses the target NiFi version. Replay representative FlowFiles, including malformed records and edge cases, and compare output and provenance with the current production results. Pay attention to scripts that depend on the flow file format, record schemas or environment values, because those differ between a test setup and production. Record the test results so they can serve as evidence for change management.

Should a team convert scripts to processors before a NiFi 2 upgrade?

Not automatically. Converting a script to a compiled processor adds build, packaging and versioning work, and the decision should rest on the script's size, reuse and performance needs rather than on the upgrade alone. Scripts that are small, stable and used in one flow can often stay as scripts with a tested inventory and a pinned version. Scripts that are large, shared across flows or on a hot path may justify a processor. Ask your team or partner to make this call per script and record the reason.

Does DeployOpen review scripted flows before a NiFi upgrade?

DeployOpen can plan and implement the inventory, the test environment, the flow and script changes and the cutover for a NiFi upgrade as a fixed-scope engagement, with scope and deliverables agreed in writing before work starts. A quote follows from that written scope, which depends on how many flows and scripts exist, how many depend on removed or renamed items, and how much testing your environment needs. Ask for the inventory as a first deliverable so the remaining scope and cost can be sized from evidence.

How scripted components connect to the rest of the platform

A scripted processor is not isolated. It draws on controller services, parameter contexts, Git-versioned flows, provenance and cluster-wide policies, and each of those links can change how the script behaves or who can change it. The cards below cover the connections to check before a script goes into a shared cluster.

Controller services the script can use

Scripts can reference controller services such as connection pools, SSL contexts and distributed caches, which keeps credentials and client lifecycles out of the script body. Confirm which controller services your scripts resolve, whether each one is scoped to the process group that uses it, and who is allowed to enable or disable it. A service disabled during a maintenance window can stop every script that depends on it, so list those dependencies before changing service state.

Parameter contexts and sensitive values

Parameter contexts supply environment-specific values to a flow, and parameters marked sensitive are encrypted at rest and hidden in the UI. Scripts should read configuration through parameters rather than hard-coded hosts or secrets, so the same flow can move between environments. Confirm which parameters are sensitive, how the sensitive properties key is managed for each node, and whether your script logs anything that could expose a parameter value.

Flow versioning through Git registries

Flow Registry Clients for GitHub and GitLab store versioned flows in a Git repository, so a script change can be reviewed, tagged and rolled back like other code. Confirm which registry client your team uses, how branches map to environments, and who may commit a flow version. Because scripts often sit inside a versioned process group, a change to script text is a flow change that needs the same review as a processor change.

Provenance for script output

Provenance records how each FlowFile was created, modified and routed, which lets you trace a transformed record back to the script run that changed it. Check whether your provenance retention covers the audit period your data rules require, and whether the attributes your script writes are recorded in a form reviewers can read. Confirm the retention settings and who can query provenance before relying on it as evidence of script behavior.

Cluster behavior for script execution

In a clustered NiFi, scripts run on every node that processes the flow, so a script that depends on local files, a node-specific host or unsynchronized state will behave differently across the cluster. Confirm how the primary node and isolated processing settings apply to your processors, and test the script on a multi-node cluster before production. Clustering coordination through ZooKeeper or Kubernetes state affects which node runs single-node tasks, so review those choices with the script design.

Security policies that govern scripts

Script execution is one of the most sensitive capabilities in NiFi, so access to scripted components should be restricted by authorization policy and by the restricted component settings your administrators control. Confirm which users can add or edit scripted processors, which authentication provider identifies them, and how script changes are approved. Treat any policy that allows broad script editing as a privilege decision, and document it alongside the rest of your NiFi hardening controls.

Questions teams ask before scripting in NiFi

Is a Groovy script enough, or should we write a real processor?

A script is usually enough when the logic is small, stateless and specific to one flow, and a real processor is the better choice when the logic is reused across flows, needs its own tests, or holds connections or state. The deciding factors are how often the logic changes, who reviews it, and how much it will be copied between environments. Scripts live inside flow configuration, so every change is a flow change. Ask your team to list the three flows that would need this logic before choosing.

What drives the cost and effort of a scripted component?

Effort follows scope more than tooling. The main drivers are the number of record schemas the script must handle, the number of external systems it calls, how many error paths must route correctly, and how much testing and documentation the team requires before production. Costs are mostly one-time (design, build, testing, rollout) with smaller recurring costs for review and changes when sources change. Ask any quote to itemize scripts by schema, external dependency and test coverage, and to state what is excluded.

How long does a scripted component typically take to deliver?

Duration depends on scope, not on the script language alone. A single transform against one known schema moves quickly, while a set of scripts covering several schemas, error routing, and a testing and approval cycle takes longer. Timelines also depend on how quickly the client team can provide sample data, access to source and target systems, and sign-off. No general figure is reliable for every environment, so ask for a timeline tied to a written list of scripts and acceptance tests.

What does the work need from our team?

Plan for three inputs: representative sample data (including malformed records), a named owner who can approve record schemas and expected outputs, and access to a non-production NiFi instance with the same restricted component settings as production. Engineers should also confirm which external systems the script may call and under what credentials. Without these inputs, testing becomes guesswork and the work stretches out. Confirm each input in writing before work starts.

Can our internal team build and maintain these scripts alone?

Yes, if the team has NiFi flow experience, comfort with Groovy and record-oriented processing, and a way to test changes before they reach production. The harder part is ongoing ownership: scripts drift when schemas change, and upgrades can change how scripted components behave. Teams that already test flows and version them through a registry usually carry this well. Teams without those practices should weigh the cost of building them before deciding to go alone.

When should we bring in a partner for scripted components?

Consider a partner when the scripts sit on a critical data path, when several flows depend on the same logic, when the team lacks time to write tests, or when the platform must pass an audit. A partner is also useful when a script must be replaced by a real processor or when an upgrade from NiFi 1.x to 2.x is planned. DeployOpen works on fixed scope agreed in writing, so ask for a scoped list of scripts, deliverables and acceptance tests in the proposal.

How do restricted component policies affect delivery?

Restricted component policies can block scripted components from running for users or instances that do not hold the right permission, and they may limit which scripting features are available. Delivery should include a review of the policy model with your security team before build starts, so scripts are not built against features that production will refuse. Confirm the current policy settings for the NiFi version you run, because the exact controls depend on that release and its documentation.

How DeployOpen scopes and delivers NiFi scripted components

DeployOpen plans and implements NiFi flows inside infrastructure you control, and treats each Groovy script as code that needs a written scope, tests and a handover. We decide with you which logic stays in a script and which moves into a custom processor, then document the choice so your team can maintain it after the engagement.

How we scope

  • Inventory every ExecuteGroovyScript, InvokeScriptedProcessor and ScriptedTransformRecord use in your current flows and rate each by volume and change frequency.
  • Agree in writing which scripts stay as scripts and which become custom processors, with the reasons recorded for each decision.
  • Confirm the target NiFi line (1.x or 2.x), the Java and Python runtimes, and the restricted component policy your organization will enforce.

How we build

  • Move script logic into well-named, versioned flows with parameters for values that change between environments, not hardcoded constants.
  • Write record transform scripts against sample datasets that cover nulls, schema drift and malformed records before they reach production flows.
  • Keep scripts in version control with reviewed changes, and check each script against the restricted components settings in your target environment.

How we hand over

  • Deliver a test suite for scripts and processors, including how to run it in your continuous integration pipeline.
  • Document each script's inputs, outputs, failure routes, dependencies and upgrade risks in a format your engineers can maintain.
  • Provide a runbook covering deployment, rollback and the checks to run before upgrading NiFi to a new major version.

How we support

  • Engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts.
  • Ongoing support, upgrade work and continuous testing are available as a retainer, which covers scripts that need changes after NiFi upgrades.
  • Ask for the written scope to name each script, its owner and its acceptance tests so the quote follows from defined work.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.