Breaking Changes
- Require Python 3.11 or newer; Python 3.10 is no longer supported. (#7449)
- Assigning over a state var's field through its state class raises
TypeError; change its default with the field'sset_defaultinstead, such asState.__fields__["count"].set_default(10). (#7516) - Mutable values provided as state var defaults are deep-copied when assigned at class creation time or passed to
set_default, so later changes to the original object no longer reach new sessions. A module-level list filled in after theclassstatement, such asoptions: list[str] = OPTIONSfollowed byOPTIONS.append(...), now starts every session empty: fill it before the class is defined, or declaredefault_factory=lambda: list(OPTIONS). (#7519) - Formatting a backend var as a string, e.g.
width=f"{State._size}px", now raisesBackendVarFormatError(aVarTypeError) instead of embedding its default value. The error names the fix: read its default withState._size.default_value(), declare a constant shared by all sessions asClassVar[...], or use a regular state var for a value the UI shows and updates. (#7456, #7496) reflex_base.utils.types.is_backend_base_variableandRESERVED_BACKEND_VAR_NAMESare removed: whether a state var is a backend var is now a property of itsFieldinget_fields(). By convention, fields named with a leading_are backend vars.is_mutable_typemoved toreflex_base.utils.types(still importable fromreflex.istate.proxy). (#7312)PageContext.get()andCompileContext.get()now raiseLookupErrorinstead ofRuntimeErrorwhen no context is active, the same as every otherBaseContextsubclass. Compiler plugins that catchRuntimeErroraround these calls should catchLookupError. (#6553)- Remove
reflex_base.constants.CustomComponents, which only the removedreflex componentCLI used. (#6425)
Features
State vars
Fieldis now the descriptor holding a state var's value, andEventHandlerbinds to the state that declares it when accessed on a state instance. (#7312)- Add
Field.set_defaultto change a state var's default, given exactly one ofdefaultordefault_factory, such asState.__fields__["items"].set_default(["a"]). (#7519) - A double-underscore state attribute (a name-mangled
__privatename or a dunder) can now be a backend var by declaring it with an explicitrx.field()value, e.g.__counter: rx.Field[int] = rx.field(0). Without one it stays a plain class attribute, like in 0.9.x. (#7465)
Configuration
SQLALCHEMY_POOL_TIMEOUT,REFLEX_BACKEND_COLD_START_TIMEOUT,REFLEX_SOCKET_INTERVALandREFLEX_SOCKET_TIMEOUTaretimedeltasettings, so they accept a unit suffix such asREFLEX_SOCKET_TIMEOUT=2m. A bare number is still read as seconds, so existing values keep their meaning. (#7138)REFLEX_AUTO_RELOAD_COOLDOWN,REFLEX_OPLOCK_HOLD_TIMEandREFLEX_STATE_MANAGER_DISK_DEBOUNCEreplaceREFLEX_AUTO_RELOAD_COOLDOWN_TIME_MS,REFLEX_OPLOCK_HOLD_TIME_MSandREFLEX_STATE_MANAGER_DISK_DEBOUNCE_SECONDS, and take a duration such as250msor5m. The old names still work and keep counting the unit in their name, with a deprecation warning; they are removed in 1.0. (#7138)- Add the
REFLEX_REDIS_MAX_CONNECTIONSandREFLEX_REDIS_POOL_TIMEOUTenvironment variables for bounding each asynchronous Redis client's connection pool. A configured cap must be at least 3 to leave room for the token manager's two pub/sub listeners and ordinary commands; the pool wait defaults to 2 seconds and must be above 0 and shorter than the state-lock lifetime. (#7179)
Other
- Add
Var.deep_equals()for structural comparison of nested frontend values. (#7208) - Add
reflex_base.utils.log.supervise_output(), which runs a command with its stdout and stderr on pipes and writes every line it and its descendants print as a JSON record; lines that already are JSON log records pass through unchanged. Output that a descendant writes after the command exits is forwarded for at most a few seconds. (#7350)
Bug Fixes
Vars and compilation
- Negative-step slices of array and string Vars now match Python at a
-1bound (e.g.State.items[-1::-1]no longer renders an empty list), and a Var step (e.g.State.items[::State.step]) no longer raisesRecursionError. (#7326) Var._replace(_var_data=...)no longer raisesTypeError: dataclasses.replace() got multiple values for keyword argument '_var_data'. (#7256)- A state that mixes in
abc.ABCor anotherABCMetaclass (class MyMixin(ABC, rx.State, mixin=True)) no longer fails with aStateValueErrorclaiming_abc_implis reserved byBaseState. (#7339) - Calling an event handler of up to four arguments on the state class with its arguments, plain or as Vars, and passing such a handler where a callable of its arguments is expected now type-check under ty, as they already did under pyright. Calls of handlers with five or more arguments can still be misreported by ty. (#7414)
- Auto-memoized
@rx.memowrapper names no longer repeat the wrapped memo component's tag. (#7004) - Pages in apps with many substates no longer intermittently fail to server-render with a 500 such as
SyntaxError: Invalid regular expression: /[^a-z-]/: Stack overflow. (#7369) - Form submissions retain ID-backed controls with unset values while omitting IDs from non-controls. (#7227)
Events and uploads
- Flatten nested client event lists before dispatch and keep processing queued events after one event fails. (#7319)
- Events sent while a buffered upload is in flight are no longer chained to it: an uploading client that disconnects no longer cancels other clients' events, the upload's response no longer waits for them, and navigating during an upload cancels the previous page's unfinished
on_loadhandlers again. Concurrent buffered uploads no longer hang or end each other's responses early, and state changes made after an upload's response has ended, such as by events a backend exception handler chains after the upload handler fails, now reach the client instead of being silently dropped. (#7357) sync=Truerx.LocalStoragevars no longer bounce between open tabs forever when the value changes while other tabs are loading, or in several tabs at once: a tab no longer writes a value it sent to the backend back over a newer one another tab stored meanwhile. (#7505)rx.download(data=State.var)percent-encodes the JSON it puts in thedata:URL, so a#or%in the data no longer truncates or corrupts the downloaded file. (#7325)- OpenTelemetry spans of top-level events enqueued during an HTTP request (a chunked upload, or a custom API route calling
app.event_processor.enqueue) no longer carry areflex.event.parent_txidnaming the event processor's root context; only chained events name the event that produced them. (#7358)
Other
- Deprecation warnings no longer point at a pseudo-location such as
<string>or<frozen importlib._bootstrap>when the deprecated call runs inside generated or frozen code; the location now names the first real user file. (#7138)
Performance
- Speed up first page loads by opening the websocket before React mounts and hydrating the page in the same round trip as the connect. (#7064)
- Lower the CPU cost of every backend event: cached computed var reads, field reads and writes, event dispatch and the JSON encoding of state deltas are faster. A computed var returning a value of the wrong type is now logged once per computed value instead of on every read, and
EventHandler.is_backgroundandEventHandler.supersedesare read once per handler, so mark the function before the handler is first used. (#7370) - Building Vars (operations, comparisons,
rx.cond,rx.foreach) is up to twice as fast, so pages that derive many Vars compile faster; the generated code is unchanged. (#7370) - Reading a cached computed var no longer re-validates its return type, and in production mode state var assignments and computed var results check only the outer type instead of walking every element. The type checks only log errors, so this changes no behavior beyond fewer element-level log messages in production. (#7353)
- Reduce event-queue overhead when prepending events and processing events with a connected socket. (#7053)
- Compile memoized components faster by reusing unchanged memo bodies instead of rendering them again. (#7123)
Miscellaneous
- Update generated apps to React 19.3, Vite 8.3.2, Socket.IO client 4.8.4, Autoprefixer 10.6.1, and PostCSS 8.5.29. Update the bundled Bun runtime to 1.4.2. (#7424)