Docs
Reference

Step Function (:function)

Quick Answer

Use this reference for the :function step schema, deterministic transform rules, and allowed helper/interop surface.

Use for sandboxed transforms.

Canonical Shape

Core fields:

FieldTypeRequiredNotes
:typekeywordYesUse :function (:code alias is deprecated)
:inputmapNoInput payload map; omitted means {}
:codeform/stringYes*Inline function body
:refkeywordYes*Reference top-level :functions entry
:loadvectorNoInput keys to load from blob refs before execution
:persistmapNoPersist function output as retained :blob, :kv, or :table

* Provide exactly one of :code or :ref.

Limits And Behavior

  • Prefer :ref for reuse and readability.
  • Keep reusable logic in top-level :functions; keep step-level :flow focused on orchestration.
  • Function steps support common output persistence with :persist; top-level :functions
    entries are reusable code definitions and do not persist by themselves.
  • Function persists use the retained/default path today. For temporary large HTTP
    responses, persist the producing :http step as ephemeral, pass the ref, and
    add :load only where hydrated content is needed.
  • Function code always receives one input map argument. If :input is omitted,
    that argument starts as {} and still includes runtime context keys such as
    :step/ctx and :flow/ctx.
  • Keep functions deterministic; avoid time, randomness, and I/O.
  • If :flow validation says it cannot resolve Long/parseLong or similar parser/helper calls,
    move that logic into a :function step or top-level :functions entry. Regular flow-body SCI
    does not expose Java interop or the helper namespace documented here.
  • Safe helpers are exposed under breyta.sandbox (preferred; pure/deterministic):
    • base64-encode (string|bytes) -> string (Base64)
    • base64-decode (string|bytes) -> string (UTF-8)
    • base64-decode-bytes (string|bytes) -> bytes
    • hex-encode (string|bytes) -> string
    • hex-decode (string) -> string (UTF-8)
    • hex-decode-bytes (string) -> bytes
    • sha256-hex (string|bytes) -> string (hex digest)
    • hmac-sha256-hex (key string|bytes, value string|bytes) -> string (hex digest)
    • uuid-from (string) -> uuid
    • uuid-from-bytes (string|bytes) -> uuid
    • parse-instant (string) -> java.time.Instant (ISO-8601)
    • format-instant (Instant) -> string (ISO-8601)
    • format-instant-pattern (Instant, pattern) -> string (UTC)
    • instant->epoch-ms (Instant) -> long
    • epoch-ms->instant (long) -> Instant
    • duration-between (Instant, Instant) -> Duration
    • truncate-instant (Instant, unit) -> Instant (unit: :seconds|:minutes|:hours|:days)
    • instant-plus (Instant, amount, unit) -> Instant (unit: :millis|:seconds|:minutes|:hours|:days)
    • instant-minus (Instant, amount, unit) -> Instant
    • url-encode (string) -> string (UTF-8)
    • url-decode (string) -> string (UTF-8)
  • Safe JSON helpers are exposed under json:
    • json/parse (string|bytes) -> data with safe identifier-like JSON object keys keywordized
      by default; it takes exactly one argument, so do not pass parser option flags
    • json/write-str (data) -> string
    • keys outside the conservative safety policy remain strings to avoid unbounded keyword interning
  • Limited Java interop is also allowed in :function code (small allowlist): java.time.*,
    java.time.format.DateTimeFormatter, java.time.temporal.{ChronoUnit,TemporalAdjusters},
    java.util.{UUID,Base64}, java.math.{BigInteger,BigDecimal}. Prefer breyta.sandbox.
  • Use the documented json/* helpers for JSON parsing and writing; lower-level parser
    namespaces are not part of the supported sandbox surface.

Canonical Example

;; In the flow definition:
;; :functions [{:id :normalize
;;              :language :clojure
;;              :code "(fn [input]\n;;                      {:value (str (:value input))})"}]

(flow/step :function :normalize
           {:ref :normalize
            :input {:value 42}})

No-input helper:

(flow/step :function :build-static-report-id
           {:code '(fn [_] "daily-ops-report")})

JSON parsing example:

(flow/step :function :parse-payload
           {:code "(fn [input]
                     (let [payload (json/parse (:body input))]
                       {:event (:event payload)
                        :id (get-in payload [:data :id])}))"
            :input {:body body-text}})

Persist transformed rows as a table resource:

(flow/step :function :persist-enriched-rows
           {:code '(fn [input] (:rows input))
            :input {:rows enriched-rows}
            :persist {:type :table
                      :table "enriched_todos"
                      :write-mode :append}})

Related

As of May 15, 2026