Breaking Changes
- Bundled Bun moves to 1.4.0, and the minimum supported Bun version rises to 1.4.0 with it. Bun 1.4 creates new lockfiles at
lockfileVersion: 2, which Bun 1.3.x cannot parse at all — so once a project'sreflex.lock/bun.lockhas been generated under 1.4, everyone building it (teammates, CI, Docker images) needs Bun 1.4 too. An existinglockfileVersion: 1lockfile is kept at v1 by Bun 1.4, even across dependency changes, so already-initialized projects are unaffected until their lockfile is regenerated from scratch. Reflex installs and manages its own Bun, so this only needs action if you pointbun_pathat your own Bun or rely on one fromPATH. (#7019)
Deprecations
reflex_base.config._load_config()is deprecated in favor of_get_config(); useget_config()to read the cached config. (#6933)
Features
- Add inert OpenTelemetry trace points and metrics around event handler execution, state acquisition, socket messages and compile stages (
reflex_base.otel) andwindow.__reflex_otelhooks in the frontend event loop and upload helper; they cost one boolean check, and import nothing fromopentelemetry, until thereflex-otelpackage enables them (reflex-baseitself does not depend onopentelemetry-api). (#6227) hybrid_propertyremains apropertysubclass at runtime, but type checkers now resolve class-level access to the frontend var's type instead of the descriptor: without a var function it follows the var equivalent of the getter's return type, and a var function may declare a type of its own. The var function may be aclassmethodorstaticmethod, may returnNoneto declare that the property has no frontend value on a class, and — likegetter,setteranddeleter— may be defined under a name of its own instead of shadowing the property's declaration. (#6812)reflex_base.utils.log.reserve_stdout()reserves stdout for a machine-readable document, rendering log records, tables, rules, prompts, spinners and progress bars to stderr for as long as it is set. (#6917)
Bug Fixes
-
A hybrid property a state inherits from a base class is no longer shadowed by state storage when the state annotates its name, which made such a state fail to instantiate. (#6812)
-
Attribute probes on vars (e.g.
inspect.iscoroutinefunctionviaunittest.mock) no longer trigger ForwardRef resolution of unrelated annotations, silencing spurious "Failed to resolve ForwardRefs" warnings and avoidingNameErrorunder PEP 649 lazy annotations on Python 3.14. (#6929) -
Avoid ModuleNotFoundError when loading
rxconfig.pyin a multi-threaded context. (#6933) -
Auto-memoized components that render identically no longer share a generated memo name, which silently dropped one of the two compiled bodies. The name now accounts for:
- module-level code emitted by
add_custom_code - dynamic imports
- app-wrap components, including
rx.textand the otherMarkdownComponentMapcomponents that all hashed alike - the defining module, so same-named components from different modules stay apart
- the identity of dataclasses and enum members, which previously hashed by shape and by
str()
(#6947)
- module-level code emitted by
-
The compatibility delta flush for background handlers that never enter
async with selfnow also runs when the handler raises, so uncached computed vars and preamble-dirty vars (likerouter_data) reach the client regardless of how the task ended. The exception still propagates to the backend exception handler afterwards; if the flush itself fails in that case, the flush error is logged instead of masking the handler's exception. (#6995) -
rx.Confignow rejects afrontend_pathwhose segments are not plain directory names (.., backslashes, or drive letters), which would otherwise relocate the production build output outside of.web/build/client. (#7044) -
Fix the Safari dev-server cache-busting plugin rendering pages as comma-separated byte values with React Router 8. The rewritten HTML now streams through instead of being buffered, and multibyte characters split across response chunks stay intact. (#7048)
-
Keep the frontend runtime stable across hot updates in
reflex run. React contexts, event dispatchers, and element refs now survive a recompile, and the state and event-loop providers are no longer remounted on every compile, so a component refreshed before its provider no longer crashes withCannot read properties of null, drops events, or reconnects the websocket. (#7071) -
Fix the post-eviction rehydrate fallback not running under
StateManagerRedis. (#7072) -
Prevent runaway page-load event chains when backend-initiated events encounter expired state. (#7073)
Performance
- Component content hashing, which auto-memoization runs for every memoized component during a compile, encodes roughly 1.2-1.3x faster on large pages. Generated memo module names change as a result; nothing outside the compiled output refers to them. (#6947)
- New opt-in dev-server knobs:
REFLEX_DEV_PROD_REACT=1serves React's production build under the Vite dev server (navigation CPU on a large app 54 → 36 ms, prod build 24 ms; edits become a full reload since Fast Refresh needs dev React), andREFLEX_VITE_WARMUP_ROUTES=1pre-transforms route modules at startup so the first visit to a page no longer waits on Vite (105–131 → 43–69 ms, or 20–32 ms with both). (#7021) - Trimmed the framework overhead around every event handler: the state fast-paths its own bookkeeping attributes, foreground handler tasks start eagerly on Python 3.12+, the computed-var expiry check only looks at interval vars, route matching is memoized per path, and socket.io handlers run inline. About 28% less CPU per trivial event and 20% more events per second per worker under concurrent load. (#7025)
- Reduce CLI startup time and memory by loading compiler plugins and optional SQLAlchemy property support only when used. (#7050)
Miscellaneous
- Bump bundled frontend pins: react-router 8.3.1, isbot 5.2.2, postcss 8.5.26, postcss-import 17.0.0, and vite 8.2.2. postcss-import 17 requires Node 22+, which already matches the Reflex minimum. (#7019)