⚠️ Tech Preview
Only the Rust bindings are a technology preview. The Rust source API (both the
minifi-nativesafe API and theminifi-native-sysFFI layer) is still evolving, and we are not yet committed to source-level backward compatibility for the Rust bindings — expect breaking changes in the Rust API between MiNiFi C++ releases until the bindings are declared stable.Under the hood, the bindings target the stable MiNiFi C API, which does provide ABI backward compatibility. This means the compiled artifact is unaffected by Rust-side churn: an extension built against an older version of these bindings will keep loading into newer MiNiFi C++ releases. You only need to rebuild against the new bindings if you want to pick up new Rust API features — upgrading the agent alone does not force a rebuild.
This project provides a safe, idiomatic, and high-performance Rust framework for building native extensions (processors) for Apache NiFi MiNiFi C++.
It is designed to offer a robust developer experience, allowing you to write powerful and reliable data processing components in safe Rust.
The framework completely encapsulates the unsafe C FFI (Foreign Function Interface) boundary, providing a pure Rust API that is fully mockable for unit testing.
The project is structured as a Cargo workspace with a clear, layered architecture:
Contains the raw, unsafe FFI bindings to the minifi-api.h C API.
Provides the public, safe, and idiomatic Rust API. This is the crate that developers will use to build their processors.
Pure Rust traits (Processor, ProcessSession, Logger, etc.) that define the abstract behavior of the MiNiFi environment.
Pure rust traits that simplify the requirements for a working processor. Pick the one that matches your processor's shape — the wrapper takes care of getting/creating the flowfile, wiring up streams, applying attributes, and transferring to the right relationship, so your code only needs to describe the transformation itself.
FlowFileTransform, but you get both an InputStream and an OutputStream and write content incrementally. Use this when the payload is too large to hold in memory or when you want to stream data through as you process it.ProcessContext, ProcessSession, and Logger — the same shape as MiNiFi C++‘s onTrigger or NiFi Java’s Processor#onTrigger. Use this when your processor doesn't fit the one-in / one-out / source molds: batching multiple flowfiles per trigger, custom routing logic, penalizing/rolling back, or anything that requires manual session.get() / session.transfer() bookkeeping.Concrete structs (CffiSession, CffiLogger, etc.) that implement the API traits by calling the unsafe functions from minifi-native-sys.
The trait system differentiates between thread-safe (&self) and single-threaded (&mut self) processors at compile time.
A full suite of mock objects allows for fast and reliable unit testing of all processor logic.
Helper crate that includes the procedural macros.
Run the behave integration tests using MiNiFi's Docker framework. This will test the release artifacts against the latest released MiNiFi native docker container. There is a handy alias to initiate all behave tests.
cargo behave
Building an extension is straightforward. The framework provides a declare_minifi_extension! macro that automatically generates the C-compatible entry points and registers your components.
declare_minifi_extension!( processors: [ (FlowFileSourceProcessorType, MultiThreaded, MyFlowFileSource), (FlowFileTransformProcessorType, SingleThreaded, MyDataTransformer), ], controllers: [ MyCustomControllerService, ] );
Build your extension as a dynamic library: cd extensions/your_extension && cargo build --release.
Locate the output artifact in target/release/ (it will be a .so on Linux, .dll on Windows, or .dylib on macOS).
Copy the library file into the MiNiFi C++ application's extensions/ directory.
Restart the MiNiFi C++ agent to automatically discover and load the new processors.
A concrete example and testing ground for extensions built using the minifi-native crate.