Skip to main content
View as Markdown

Data & State

Three families that move values rather than perform side effects: data reshapes what has already flowed through the workflow, state remembers values between runs, and filter decides whether the run continues at all.

Data — In-Memory Transforms

Ten operators, all of them pure: they read from earlier steps and produce a new value.

Operator Props Description
set value Set a value for later steps. Read back at steps.<name>.value.
aggregate input, function, field?, groupBy? Reduce an array — sum/avg/min/max/count, optionally grouped.
sort input, field, direction? Sort an array by field (asc default / desc).
limit input, count Take the first count items.
deduplicate input, key Remove duplicate items by key.
merge left, right, joinKey? Merge two arrays — joined on joinKey, or concatenated when omitted.
split input, size Chunk an array into sub-arrays of size.
compare left, right, key Diff two arrays by keyadded / removed / unchanged.
lookup input, key, value Find the first item whose key field equals value.
validate-config config, format? Validate a Sovrium config (json default / yaml) → { valid, errors }.
app.yaml
- name: revenueByRegion
  type: data
  operator: aggregate
  props:
    input: '{{fetchOrders.result}}'
    function: sum
    field: amount
    groupBy: region

Three behaviours that surprise people:

  • aggregate needs field for sum, avg, min and max. Only count may omit it.
  • lookup returns one record, not a key→value map — it is find, not indexBy.
  • set takes a string. value is a template string, so a bare YAML number, list or object is rejected. Its result is at steps.<name>.value, not .result.

State — Cross-Run Key-Value Store

Five operators persisting values between runs: counters, cursors, dedup markers — anything a single run cannot hold.

Operator Props Description
get key, namespace? Read a stored value.
set key, value, namespace?, ttl? Store a value, optionally with a time-to-live.
increment key, amount?, namespace? Atomically add amount (default 1; negative decrements).
delete key, namespace? Remove a stored value.
list prefix?, namespace?, limit? List keys, optionally filtered by prefix.
app.yaml
- name: bumpCounter
  type: state
  operator: increment
  props: { key: 'orders:{{trigger.data.record.region}}', namespace: metrics }

Both optional scoping props are format-constrained, and a value outside the format fails config decode rather than at runtime:

Prop Format Valid Rejected
namespace Lowercase kebab-case, starting with a letter. metrics, sync-state Metrics, my_ns
ttl A number followed by ms, s, m, h or d. 30s, 24h 1 hour, 3600

Filter — Conditional Gating

One operator, deciding whether the workflow proceeds.

Operator Props Description
continue condition, onFalse? Evaluate a condition group; on false, stop (halt the run) or skip (skip to the next action). Defaults to stop.
app.yaml
- name: onlyPaid
  type: filter
  operator: continue
  props:
    condition:
      conditions:
        - field: '{{trigger.data.record.status}}'
          operator: equals
          value: paid
    onFalse: stop

This is the right tool for narrowing a trigger that cannot narrow itself — an auth trigger fires on every sign-up, and a filter/continue first step reduces it to the sign-ups you care about. Reach for path/branch instead when both outcomes need to do something.

Crypto — Hashing & HMAC

Moved to Crypto & Digest.

Digest — Batch & Release

Moved to Crypto & Digest.

Last updated August 11, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.

Built with Sovrium