Deprecations
VarData(position=...)andHooks.HookPositionare deprecated and ignored: hooks render in declaration order. Remove thepositionargument; to place a hook after another one, put the one it reads in itsVarData(hooks=...). (#7586)reflex_base.utils.format.format_data_editor_columnis deprecated and will be removed in 1.0;rx.data_editorapplies the column defaults itself. (#7607)
Features
- Add the experimental
react_compilerconfiguration option, also available asREFLEX_REACT_COMPILER, to opt in to automatic React component memoization. (#7234) - Event props and the events an event handler returns accept any sequence of events, e.g. a tuple or a variable typed
list[EventSpec], not only a list literal. The newreflex_base.event.event_sequencehelper returns such a value as a sequence of events, wrapping a single event in a list. (#7402) - The compiled context module exports
stateSchema, a hash of the state tree the frontend was built for, and the frontend sends it in the socket.io CONNECTauthpayload under thestate_schemakey. The backend answers a mismatch with the newstate_mismatchsocket event; in production, the frontend then reloads once per cooldown window or shows a "new version available" banner, while in development it only warns in the console. (#7553) - Add
reflex_base.vars.get_leaf_vars, which returns the vars a var reads by unwrapping var operations, casts, literal containers and function bodies, for example to list a derived var's dependencies in a React hook's dependency array. (#7606) - Add the
trusted_proxy_hopsconfiguration option for safely resolving client IPs from trusted proxy headers. (#7614)
Bug Fixes
TypedDictform data honorsRequiredandNotRequired, including insideAnnotated, in modules usingfrom __future__ import annotations: aNotRequiredfield no longer needs a matching form control. (#7386)- An event handler stored outside a state, e.g. in a component or dataclass field, now type-checks as the handler instead of a bound function, and a handler read through a state instance is typed as a function returning
Any. (#7401) LiteralObjectVar.createis typed to take any value that serializes to a mapping, such as a dataclass, as it does at runtime, not only a mapping. (#7403)- The CDN fallback for an unbundled sub-path dynamic import now puts the sub-path before jsdelivr's
/+esm, so it resolves instead of returning 404. (#7405) - ty now reads an optional model, dataclass or mapping field (
rx.Field[X | None]) on the state class asObjectVar[X], as pyright already did, instead ofObjectVar[X | None]. (#7413) - Cancel pending hydration and page-load event chains when their client disconnects. (#7415)
- Calling an upload handler with
rx.upload_files(...)orrx.upload_files_chunk(...)as its only argument, as the upload docs show, now type-checks under pyright and ty, for a handler takinglist[rx.UploadFile]orrx.UploadChunkIterator. (#7419) - Frontend updates and events now keep working when a backend update names a substate the compiled frontend does not know. Reflex skips that substate and reports it once per connection. (#7435)
- Fix a blank page with
Maximum call stack size exceededin apps with thousands of state classes. State is now read from one shared store, so the React provider tree no longer grows with the number of states. (#7441) - Raise descriptive errors when page or compile contexts are accessed outside compilation. (#7517)
- Make
StringVarlength, indexing, and slicing count Unicode code points so operations do not split valid surrogate pairs. On aNonestring these operations now behave as if it were empty. (#7518) - A frontend error event that carries no
Errorobject, such as the benignResizeObserver loopnotification, no longer throws insidewindow.onerrorand is now reported tohandle_frontend_exception. (#7544) - Editing one tab no longer leaves other
sync=Truebrowser storage vars that share its storagenamestale in other tabs; every such var is now synced, not only the last one declared. (#7545) - A state var annotation that names an undefined symbol, such as
items: list[Item] = []underfrom __future__ import annotations, raisesNameError: name 'Item' is not definedagain instead of an unrelatedTypeErrororAttributeError. This also covers vars without a default, backend vars, and Python 3.14 annotations without the__future__import. (#7547) - Report a hydrate message that exceeds the server's message size limit, with its size and the limit, instead of sending it and retrying. Reduce browser storage data and reload to recover. (#7551)
- On POSIX,
reflex run --jsonforwards SIGINT to its child process, so supervisors that signal only the Reflex PID can stop the app cleanly. (#7558) - Raising a negative number or a negated var to a power, such as
(-State.x) ** 2, now compiles to valid JavaScript instead of failing the frontend build with "A unary expression with the '-' operator cannot be used as the left operand of an exponentiation expression". (#7565) - Write the Tailwind
importantoption to the generatedtailwind.config.jsunder theimportantkey. It was emitted asimportants, so Tailwind ignored it. (#7573) - A background task that re-enters an expired session now rehydrates the loaded states. The browser drops their stale values and keeps its route and browser storage; its next event runs the current page's on_load. (#7585)
- Component hooks render in the order they are declared and merged, so a hook always comes after the hooks it reads. Before, a component whose prop and
add_hooksVar read the same state could render a hook before the state declaration it reads and fail with aReferenceError. A hook that reads state must carry it: returnrx.Var(f"const x = {State.value}")fromadd_hooks, not a plain string built withstr(State.value). (#7586) - Passing a plain
dicttoformat_propno longer raisesAttributeError; the dict is JSON-encoded like any other literal. (#7587) - Resolve Pydantic v2 model field types without emitting deprecation warnings, while retaining Pydantic v1 compatibility. (#7592)
- Retry with backoff and show the connection error when the server or a proxy closes the connection before it is established, for example when browser storage makes the hydrate message too large, instead of reconnecting in a tight loop. (#7605)
- Event handler arguments hinted as an
rx.Modelno longer emit aPydanticDeprecatedSince20warning for every key of the payload. (#7636) - Upgrade the default Bun version to 1.4.4, which removes compromised emSign certificate authorities from its bundled trust store. (#7639)
Performance
- Add the
REFLEX_BACKEND_START_METHODenvironment variable to choose how production backend workers are started (fork,spawn, orforkserver). (#7079) - Unchanged objects and arrays in state updates now keep their previous identity on the frontend, so memoized components skip re-rendering them, and an update that changes nothing no longer re-renders at all. (#7273)
- A running background event handler no longer keeps the state tree it was dispatched with alive once it has entered
async with self. With the Redis state manager, every long-running background task used to hold an extra copy of the session's state. (#7447)
Documentation
- Document the supported
BaseStateMetacontract for custom state metaclasses, including thestate_rootandmixinclass keywords and the reserved_reflex_state_rootattribute. (#7626)
Miscellaneous
- Update generated apps to React 19.3.1, Vite 8.3.4, PostCSS 8.5.30, and postcss-import 17.0.1. (#7645)