Skip to main content
Wherever a processor needs logic — a filter predicate, a mapping, an aggregation step — you write a Spring Expression Language (SpEL) expression. The editor is type-aware: it knows the key and value types at that point in the topology and gives you completions, live validation, and highlighting to match.

Roots: key and value

In most expressions two root identifiers are in scope:
  • key — the record key
  • value — the record value
Some operators expose a different scope, with extra variables (prefixed #, the standard SpEL convention): The editor highlights the identifiers that are valid in the field you’re editing, and the validator rejects out-of-scope ones with a hint (e.g. Unknown root identifier: aggValue. Use key, value or #aggValue.).

Types drive the editor

What you can do with key and value depends on their configured types (the stream’s default serdes, per-node overrides, or the editor’s type hints):
  • JSON / JSON Schema / Avro / Protobuf — map-style access: value['field'], value.containsKey('field'). String methods are not available on the record itself.
  • String — string methods: value.length(), value.contains('x'), value.toLowerCase(). No map-style access.
  • Numbers (Integer, Long, Float, Double, Short) — numeric methods and arithmetic.
  • Bytes — raw byte access.
Completions follow the same rules, including for chained calls — after value.someCall(). the editor infers the intermediate type and suggests only what fits.
The editor box is resizable — drag its corner to make room for longer expressions.

Producing multiple values

flatMap / flatMapValues emit several records from one input. Return an inline list literal:

Calling Java

Static calls on a small allowlist of safe types are available via T(...): Math, the numeric box types, String, Map/List, UUID, and Kafka’s Bytes.
Expressions are deliberately sandboxed: T(...) refuses everything outside the allowlist (no Runtime, System, ProcessBuilder, …) and the new operator is blocked entirely — use inline list literals {'a','b'} where you would have constructed an array. The editor won’t suggest blocked constructs, and the validator rejects them.

Custom functions

Operators can extend the vocabulary without recompiling Alginte: register public static Java methods (from a JAR on the classpath) under kafka.streams.transformation.functions, and call them as #name(args) in any expression — with full editor support.
Resolution is fail-fast at startup: a missing class, a non-static method, or an ambiguous overload aborts with a precise message instead of failing later mid-stream.