¶
The re-frame Clojars page contains dependency coordinates for Maven/deps/Lein.
Unreleased¶
Nothing yet.
1.4.7 (2026-04-30)¶
A small follow-up to 1.4.6 in response to user feedback against the new
re-frame.macros namespace introduced there. Two themes: complete the
mirror so it's actually a drop-in for re-frame.core, and fold in a
parallel mirror for re-frame.alpha. The re-frame.macros namespace
itself has been renamed to better describe what it is (see Changed
below).
Changed¶
- Namespace rename:
re-frame.macros→re-frame.core-instrumented. The instrumented mirror ofre-frame.coreintroduced in 1.4.6 has been renamed to better describe what it is rather than how it's implemented. There-frame.macrosnamespace is gone — change your:requirefrom[re-frame.macros :as rf]to[re-frame.core-instrumented :as rf]. Behaviour is unchanged.
Added¶
re-frame.core-instrumentedis now a complete drop-in forre-frame.core. The 1.4.6 cut covered 8 source-meta-capturing surfaces (dispatch,dispatch-sync,subscribe,reg-event-db/-fx/-ctx,reg-sub,reg-fx); user feedback flagged thatreg-sub-rawwas missing, and that the partial coverage broke the alias-swap pattern for any real-world app that also touchedclear-event,inject-cofx,path,console, etc. This release brings the namespace to parity:- New source-meta-capturing macros:
reg-sub-raw,reg-cofx,reg-event-error-handler,dispatch-with,dispatch-sync-with,dispatch-and-settle. Each decorates the registered handler / dispatched vector with{:file :line}under the appropriate registrar kind. CLJS production builds (goog.DEBUG=false) DCE the meta-attach branch the same way the existing macros do. -
Pure passthroughs (def re-exports): every other public
re-frame.coresymbol is re-exported as adefso the alias swap covers the full surface —clear-event,clear-sub,clear-fx,clear-cofx,clear-subscription-cache!,clear-global-interceptor,inject-cofx,path,enrich,after,on-changes,->interceptor,debug,unwrap,trim-v,reg-global-interceptor,set-loggers!,console,tag-schema,validate-trace?,set-validate-trace!,register-trace-cb,remove-trace-cb,register-epoch-cb,remove-epoch-cb,assemble-epochs,version,query-v-for-reaction,live-query-vs,get-coeffect,assoc-coeffect,get-effect,assoc-effect,enqueue,make-restore-fn,purge-event-queue,add-post-event-callback,remove-post-event-callback, plus the legacyregister-handler/register-subaliases. -
re-frame.alpha-instrumented— the same instrumentation pattern, mirroringre-frame.alpha. Source-meta capturing macros for the dispatch/registration surface alpha re-exports from core (dispatch,subscribe,reg-event-db,reg-sub, etc.); pure passthroughs for the rest of alpha's surface so the swap from[re-frame.alpha :as rf]to[re-frame.alpha-instrumented :as rf]is alias-only. Alpha-specific surfaces (reg,sub,reg-flow) pass through as functions for now — instrumenting them is deferred until alpha stabilises.
1.4.6 (2026-04-29)¶
This release is focused on making re-frame more amenable to pair programming with an AI like Claude Code or Codex.
Specifically, the changes included in this release are focused on supporting
re-frame-pair, a SKILL which teaches an AI how to interact
with, and introspect, a running re-frame application.
Along the way, these improvements help other tooling, like re-frame-10x, which is human oriented.
The focus has been on new namespaces like re-frame.tooling and re-frame.macros, and
on tracing code execution within a running application.
See the Debugging & Instrumentation guide and the
re-frame.tooling page for the longer-form story.
Added¶
Discoverability¶
re-frame.tooling— discoverability namespace for tooling consumers. Re-exports the supported surface (dispatch overrides, trace cb / schema, live subscription cache, registrar atom) without renaming or moving any symbol — source-of-truth definitions stay in their original namespaces. Require ONE namespace to find the contract:(require '[re-frame.tooling :as rft]) (rft/dispatch-with [:my-event] {:effect-id (fn [_] ...)}) (rft/register-trace-cb :my-tool (fn [traces] ...)) @rft/query->reaction ;; live subscription cache @rft/kind->id->handler ;; registrar atom
Source-meta opt-in (re-frame.macros)¶
re-frame.macros— drop-in macro replacements/mirror for keyre-frame.corefunctions. These macros capture call-site{:file :line}information to facilitate tracing and, as a result, tooling likere-frame-10xandre-frame-paircan accurately understand how the dynamics of a running application relate to source code:- functions mirrored —
re-frame.macros/dispatch,dispatch-sync,subscribe,reg-event-db,reg-event-fx,reg-event-ctx,reg-sub,reg-fx
- functions mirrored —
-
to use this new feature, swap
re-frame.coreforre-frame.macrosin your:require:;; function API — no source-meta (:require [re-frame.core :as rf]) ;; macro API — same call shape, source-meta captured (:require [re-frame.macros :as rf]) -
In CLJS production builds (
goog.DEBUG=false) the meta-attach branch is eliminated by Closure dead-code elimination, so the macro reduces to a barere-frame.core/...call with zero runtime overhead. - Going forward you should prefer to use these macros instead of
their function counterparts, UNLESS you need them in a value
position, for example
(apply reg-sub ...),(map reg-event-db ...),(partial reg-fx ...).
Dispatching events¶
- diagnostic versions of dispatch, useful in testing and experimentation.
-
re-frame.core/dispatch-with,dispatch-sync-with— fireeventwith selected fx handlers temporarily mocked/substituted for the duration of the dispatch and any synchronous:fx [:dispatch ...]cascade. Stubs ride on event metadata, not global state, so no try/finally is needed and overlapping calls don't interfere. Useful for dry-run dispatches in dev (observe:effects/app-dbchange while stubbing:http-xhrio/ navigation), dispatch-scoped test stubs, and reversible REPL exploration.(re-frame.core/dispatch-with [:user/login {:email "..." :password "..."}] {:http-xhrio (fn [req] (re-frame.core/dispatch (conj (:on-success req) {:stubbed true})))}) -
re-frame.core/dispatch-and-settle— allows you to fireeventand return a deferred value that resolves once the event AND its synchronous:fx [:dispatch ...]cascade have settled. Resolves to{:ok? true :root-epoch <id> :cascaded-epochs [<id> ...]}on success or{:ok? false :reason :timeout :event ev :captured-epochs [...]}on timeout. CLJS returns a JS Promise; CLJ returns aclojure.core/promise. Accepts anoptsmap::timeout-ms(default 5000),:settle-window-ms(default 100),:include-cascaded?(default true), and:overrides— an fx-id → stub-fn map composed withdispatch-with's contract and propagated through the cascade. Useful for tests and diagnostics that need to wait for a cascade to finish before asserting on the resulting state.;; CLJS — await the promise (-> (re-frame.core/dispatch-and-settle [:cart/checkout]) (.then (fn [result] ...))) ;; Override selected fx while awaiting the cascade @(re-frame.core/dispatch-and-settle [:cart/checkout] {:overrides {:http-xhrio stub-success}})
Subscription accessors¶
re-frame.core/live-query-vs,re-frame.core/query-v-for-reaction— public, cache-shape-stable accessors for tool consumers that previously had to fake them by walking internalquery->reactionkeys.live-query-vsreturns a snapshot sequence of every currently- live cached query vector. Useful as a sub-cache-size probe:(count (re-frame.core/live-query-vs)).query-v-for-reactionis the inverse ofsubscribe: given a reaction held by tooling, return the query-v that produced it (or nil if unknown / disposed). Backed by an object-identity- keyed reverse map maintained alongside the subscription cache; entries clear when the reaction is disposed. The reverse-map insert is gated onis-trace-enabled?so it costs nothing in production builds without tracing.
Tracing¶
- re-frame produces detailed trace data describing how an event is processed and how the subsequent reactive UI updates occur.
-
re-frame.core/tag-schema— describes the schema for this trace (for use by tooling).- The schema describes
:tagsfor every op-type re-frame emits (:event,:event/handler,:event/do-fx,:sub/create,:sub/run,:sub/dispose,:render,:raf,:raf-end,:reagent/quiescent,:sync). Each entry lists:requiredkeys,:optionalkeys, and a one-line:doc. Doc-only by default; downstream tooling reads it as a load-bearing contract for the trace stream. Adding a key is additive; renaming or removing a key is breaking and must go through a deprecation cycle.
- The schema describes
-
re-frame.core/validate-trace?,set-validate-trace!— opt-in runtime trace tag validation. With validation on,finish-tracechecks:tagsagainsttag-schemaand warns viaconsole :warnon missing required keys or unknown keys. Off by default; intended for dev / CI to catch schema drift in re-frame core and in third-party trace emitters early.(re-frame.core/set-validate-trace! true) -
re-frame.core/register-epoch-cb,remove-epoch-cb,assemble-epochs— assembled-epoch callback alongsideregister-trace-cb. Whereregister-trace-cbdelivers the raw trace stream,register-epoch-cbdelivers one assembled record per:eventtrace, partitioning each batch into the dispatch / handler / do-fx / sub-create / sub-run shape downstream tools want. Each epoch carries its own:dispatch-idand:parent-dispatch-id; consumers wanting a tree-shaped view of a user-fired event plus its chained children build it post-delivery by walking parent-id pointers. Same gating asregister-trace-cb(opt-in via:closure-definesre_frame.trace.trace_enabled_QMARK_ true) and same delivery boundary (debounced batches on CLJS, synchronous on CLJ at the outermost trace's finish). The cascade- settled signal that some consumers want lives separately underdispatch-and-settle— keeping the two decoupled letsregister-epoch-cbship without depending on async-settle infrastructure.
Diagnostics¶
-
re-frame.core/version— runtime-readable string identifying the deployed re-frame artifact. Useful for tooling, instrumentation, and version-floor probes (e.g. re-frame-pair'sread-version-of) that need to know which re-frame they're running against without parsingpom.xmlat runtime. Re-exported fromre-frame.config/version; mirrored asre-frame.alpha/version. -
re-frame.config— new namespace exposingversion. Under CLJS this is agoog-define; apps embedding re-frame can override at build time via shadow-cljs:closure-definesto bake the resolved git-tag version into release artifacts::closure-defines {re-frame.config/version :day8.dev/git-app-version}
Modeled on re-com.config/version so version-probe code can read
both libraries with the same global-path lookup
(goog.global.<lib>.config.version).
Changed¶
re-frame.registrar/register-handlernow logs a console warning on duplicate handler registrations in production builds (goog.DEBUG=false) or before re-frame's hot-reloadloaded?gate is set. Hot-reload from figwheel / shadow-cljs after page load remains silent (the same gate already used elsewhere). In production a duplicatereg-event-db/reg-sub/reg-fxfor the same id almost always indicates a bug — typo, copy-paste, ns load order — so the warning surfaces it loudly. Apps relying on silent overwrite (rare, almost certainly bug-shaped) should investigate.
1.4.5 (2026-04-12)¶
Fixed¶
- Unreachable code warning during advanced compilation in
validate-inputs(#827) - Broken documentation link in cofx-as-fx warning message (#834)
Changed¶
- Upgraded shadow-cljs in examples to 3.2.0 for ClojureScript 1.12.42 compatibility (#833)
- Removed alpha toggle demo from todomvc example
- Pinned GitHub Actions to commit SHAs for supply chain security
- Migrated docs deployment to Pages artifact
1.4.4 (2026-01-03)¶
Added¶
:foreverand:no-cacheSubscription (alpha) lifecycles. See: https://day8.github.io/re-frame/FAQs/alpha/#benefit-more-lifecycles- Flows (alpha): added tracing. See day8/re-frame-10x v1.11.0 for an implementation of tracing in the "flows" tab.
Fixed¶
-
Flows (alpha) now run in response to (non-alpha) re-frame.core events
-
Subscription (alpha) signal & calculation functions always receive a map as the query, even when invoked with a vector query, or invoked with
re-frame.core/subscribe. This is meant to provide stability, so users can writereg :subhandlers wtihout needing to think about whether the callsite is alpha, legacy, map or vector.
Changed¶
-
Subscriptions (alpha) are more careful to ensure the memory-safety of their input signals. See: https://day8.github.io/re-frame/FAQs/alpha/#benefit-safe-subscriptions
-
Changed flows to calculate the new app-db earlier in the chain.
- Benefit: user-defined interceptors can access post-flow app-db value.
- Drawback: they can't access the value of app-db directly resulting from the event handler.
-
Drawback: they can't access flow-related effects like
:reg-flow. -
Added a :re-frame/pre-flow-db key to the context
- This way, user-defined interceptors can still access the app-db value resulting directly from the event handler.