Status: Accepted (2026-07-15); amended (2026-07-22) — the transactor-path
runtime is now the GC-less cljrs-tx interpreter (see Addendum).
Datomic's :db/fn transaction functions run arbitrary code on the transactor
inside transaction expansion. Options: native Rust built-ins only (defer user
functions), an unrestricted cljrs environment (trusting deployments), or a
restricted cljrs interpreter. The transactor is the availability bottleneck
of the whole system; code running inside its pipeline must be bounded.
User transaction functions are cljrs code stored as datoms, executed on the
transactor in a sandboxed cljrs-interp environment: pure-clojure.core +
read-only db API namespace allowlist, no I/O or interop escape, no mutable
concurrency primitives, per-invocation fuel/allocation budgets with clean
transaction abort on exhaustion. Functions must be deterministic in
(db, args); the log stores expanded datoms so replay never re-executes
functions. Core primitives (:db/cas, :db/retractEntity) are native Rust,
not sandboxed code.
cljrs-interp — an upstream dependency risk
tracked at the M5 checkpoint (fallback: watchdog-thread enforcement with
namespace restriction only).cljrs-tx transactor runtimeUpstream clojurust now ships cljrs-tx, a purpose-built transaction-function
runtime: a tree-walker-only interpreter where each invocation runs in a fresh
bounded arena (no GC) under gas, managed-memory, and call-depth budgets, with
the whole environment destroyed when the call returns. The transactor's
:db/fn expansion now uses it directly (corium-transactor feature cljrs,
on by default), replacing the worker-thread sandbox from the original
decision in the transactor path:
db argument, and the read-only corium.api host
functions (q, pull, entity, datoms, time views, basis-t)
interpret the token against the database value they close over — the
HostFn seam serializes and validates every crossing value.cljrs-tx requires the cljrs stack's no-gc
mode, a cargo feature that unifies onto every cljrs crate in the same
build. corium-cljrs (the GC-mode Clojure client API) is therefore
excluded from default workspace builds and is built standalone; it remains
the client-side embedding surface and no longer sits in the transactor
path.Can you improve this documentation? These fine people already did:
Casey Marshall & ClaudeEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |