v0.10.0a1
Pre-release
Pre-release
Breaking Changes
- Remove the
reflex componentCLI (init,build,share,install) and theCustomComponentsconstants. Wrap React libraries directly in your app as described in the wrapping React docs, and start reusable component packages from the component template, which builds, tests, and publishes them with standard Python tooling. (#6425) - A substate may now declare a var or computed var with the same name as an inherited var: it gets an independent one of its own, instead of raising
BaseVarShadowsInheritedVarErrororComputedVarShadowsBaseVarsError. A dynamic route arg only conflicts with a var of the state it is installed on. Assigning an undeclared state attribute still raisesSetUndefinedStateVarErroroutside of prod mode, but no longer in prod. The internal class mapsbackend_vars,inherited_varsandinherited_backend_vars,get_skip_vars()and the instance_backend_varsare removed: useget_fields(), whose fields know the state they belong to. States saved by this release still load in workers of the previous one, so rolling deploys sharing Redis keep working, with one exception: while old workers remain, an in-place change to a mutable backend var (likeself._items.append(x)) made on an old worker to a state saved by this release is not persisted. Assigning backend vars, and any change to frontend vars, is unaffected. (#7312)
Features
- The duration settings read by the app and the state managers take a unit suffix:
SQLALCHEMY_POOL_TIMEOUT,REFLEX_SOCKET_INTERVALandREFLEX_SOCKET_TIMEOUTaccept values such as2m, andREFLEX_AUTO_RELOAD_COOLDOWN,REFLEX_OPLOCK_HOLD_TIMEandREFLEX_STATE_MANAGER_DISK_DEBOUNCEreplace the_MS/_SECONDSnames, which still work with a deprecation warning until 1.0. A bare number is read as seconds. (#7138) - Set
REFLEX_REDIS_MAX_CONNECTIONSto cap each Redis client's connection pool (the state manager, the token manager and the health check each use their own client). Once a pool reaches the cap, requests wait up toREFLEX_REDIS_POOL_TIMEOUT(default 2s, which must be above 0 and below the configured state-lock lifetime) for a free connection instead of opening new ones. (#7179)
Bug Fixes
- Fixed
reflex db makemigrations/migratecrashing withCompileErrorwhen autogenerating a migration that adds a column with a callable default (e.g.default_factory=datetime.nowordefault=uuid.uuid4) to an existing table; callable defaults are now evaluated before being carried as a SQLserver_default. (#6706) - Serve valid dynamic-route URLs (e.g.
/articles/7) with HTTP 200 instead of 404 when loaded directly in self-hosted prod static serving, reserving 404 for genuinely unknown paths. (#6996) - When a project keeps using npm because
reflex.lock/only haspackage-lock.json(for example after a run withREFLEX_USE_NPM=1), Reflex now logs why and how to switch back to bun withREFLEX_USE_NPM=0. (#7093) - Reflex now checks the Node.js version before running npm, so an unsupported Node.js no longer leaves npm lockfiles behind that switch later runs to npm. (#7210)
- Preserve ID-based form controls through automatic memoization while excluding IDs on non-controls from submissions. (#7227)
- Avoid reinstalling frontend packages on every compile or hot reload when bun or npm only changes the formatting of
package.json. (#7236) reflex dbcommands run without thedbextra installed now exit with the "pip install reflex[db]" message instead of a raw traceback. (#7259)- Fix
TypeError: refs._client_state_set... is not a functionwhen a component sets a globalrx._x.client_statevalue before any component reading.valuehas mounted, such as when the reader sits behind anrx.cond. (#7286) - An editable install (
uv sync,pip install -e .) no longer overwrites.pyistubs that the checkout already has. A checkout missing any of them still gets them generated. (#7303) - In a background task on a substate, in-place changes to a mutable var inherited from a parent state (like
self.items.append(...)) are now sent to the client and persisted. (#7312) - Fix stylesheet edits in
assets/not applying in dev mode until a manual reload. The global stylesheet<link rel="preload">is now emitted only in production builds, so Vite's CSS hot update swaps the real stylesheet link again. (#7317) - The memory and disk state managers now free expired session states right away instead of waiting for a garbage collection pass, and the disk state manager no longer keeps a lock for every expired session. (#7318)
reflex dbcommands only requiresqlalchemyandalembic, so apps that use plain SQLAlchemy models withoutsqlmodelcan run migrations again. (#7322)- A page URL with a
selfquery parameter (e.g./post?self=1), or a request header namedself, no longer crashes router data parsing and leaves the page unhydrated. (#7324) reflex runnow stops its frontend on SIGTERM and SIGINT without a TTY, while keeping frontend workers in the CLI process group so a hard kill also stops them. (#7328)- A state stored in Redis that can no longer be unpickled, for example because a deploy moved or deleted a class held in a state var, is now replaced with a fresh state like a schema mismatch, instead of failing every event from that tab until the Redis key expires. (#7329)
- On Windows, the development backend no longer closes its listening socket twice when it releases the port, which could close another socket that had reused the handle and make it fail with
OSError: [WinError 10038]. (#7348) reflex run --jsonnow emits every output line as a JSON record:print()output from the app, subprocess output, and worker tracebacks (as one record with anexceptionfield) no longer break the JSON-lines stream. (#7350)- Fix a race with
REFLEX_OPLOCK_ENABLEDwhere an instance could take an opportunistic lease before its Redis lock notifications were active, making other instances wait out the full hold time for the same token. (#7372) - Stop logging
asyncio.CancelledError: lifespan_cleanupas an error when a running coroutine lifespan task is cancelled at backend shutdown or hot reload. (#7392)
Performance
- Speed up first page loads by combining hydration with the websocket connect and sending only values that differ from compiled defaults. Reduce Redis state-tree read/write overhead and avoid repeated class metadata computation in apps with many states. (#7064)
- Reuse unchanged memo-body analysis during module emission to reduce repeated rendering and artifact collection. (#7123)
- Skip the linked-client fan-out on events that changed nothing shared, so an app that defines an
rx.SharedStateno longer resolves the runningAppon every event. (#7237) - Reading a state var is about 4x faster, and setting one about 7x faster (15x in prod mode): vars, computed vars and event handlers are now descriptors on the state class that declares them, instead of every attribute access going through
BaseState.__getattribute__. (#7312) - Process events with less CPU on the backend: iterating, sorting and reading list and dataclass state values costs 25–75% less, and the redis state manager writes the changed states of a session in one round trip. (#7370)
Documentation
- Document the dict form for
rx.toastactionandcancelprops instead of referencing the non-publicToastActionclass. (#7327)