Release Notes
BREAKING CHANGES
Database support is now opt-in (#6293)
pydantic, sqlmodel, and alembic have been removed from Reflex's base dependencies. If your app uses rx.Model, rx.session, database migrations, or any other DB feature, you must now:
- Install the DB extra:
pip install 'reflex[db]~=0.9.0' - Set
db_urlin yourrxconfig.py, for example:
config = rx.Config(
app_name="my_app",
db_url="sqlite:///reflex.db",
)Apps that do not use the database can drop these dependencies entirely.
- remove pydantic sqlmodel alembic dep by @adhami3310 in #6293
- do not set db_url to sqlite by default by @adhami3310 in #6347
Event processing moved to the backend (#6267)
The primary responsibility for chaining and queueing events has moved from the frontend to the backend. This removes an extra client round-trip when chaining events with yield, but it requires changes for anyone reaching into the internals.
Removed / renamed (Python):
App.process_backgroundandrx.app.processare removed — use the newapp.event_processor(aBaseStateEventProcessor/EventProcessor) which owns the full event lifecycle, including background tasks.App._background_tasksreplaced byApp.event_processor._tasks.State.class_substatesis removed — useState.get_substates()instead.AppHarnessstate helpers removed (reflex/testing.py):state_manager,get_state(token),set_state(token, **kwargs),modify_state(token),poll_for_clients(), and_reset_backend_state_manager()are all gone. Tests should drive state changes through the app's event processor / in-app assertions instead.Event.tokenfield removed — the token now lives onEventContext.Event.substate_tokenreplaced by theEvent.state_clsproperty (resolved via the new registry).Deltatype refined fromdict[str, Any]todict[str, dict[str, Any]](nested by substate name).StateManager.create()no longer accepts astate=argument — state classes are discovered from the registry.StateToken(reflex/istate/manager/token.py) replaces raw"client_token_substate"strings across all state managers (disk / memory / redis).StateTokenandBaseStateTokenare exported fromreflex.EventHandlerSetVar.state_clsrenamed to.state(to matchEventHandler).fix_eventsremoved from the semi-public event API — useEvent.from_event_type().get_hydrate_eventremoved — hydration is now handled internally; simulated pre-hydrated states are gone.
Frontend (state.js):
applyEvent()now returnsvoid(previously returnedbool); the internalevent_processingflag was removed.StateUpdateonly includes non-empty fields to reduce bytes over the wire.- Params are passed around as a ref instead of inline.
Production mode runs on a single port (#6297)
Production deployments now always serve the frontend and backend on the same port (what used to be --single-port). Consequences:
- You cannot pass different
--frontend-portand--backend-portvalues in--env PROD. - The frontend is now served via Starlette
StaticFilesthrough granian/uvicorn instead of a separatesirvprocess. - The
sirv-clinpm dependency has been removed. prerequisites.check_running_mode()now returns aRunningModeenum (FRONTEND_ONLY,BACKEND_ONLY,FULLSTACK) instead of a(bool, bool)tuple.
- ENG-8961: Single port is only prod option by @adhami3310 in #6297
- make sure running prod backend only uses backend port by @adhami3310 in #6346
state_auto_setters default is now False (#6292)
Auto-generated setters (set_<var>) are no longer created by default. Define explicit event handlers for setting state vars, e.g.:
class MyState(rx.State):
count: int = 0
@rx.event
def set_count(self, value: int):
self.count = valueExisting apps can opt back in temporarily with rx.Config(state_auto_setters=True, ...), but the option is now deprecated and will be removed in 1.0. Explicitly setting state_auto_setters (either value) will emit a deprecation warning.
Other removed deprecations (#6292)
PydanticV1support got deleted (alongrx.Base). Please migrate to either dataclasses or PydanticV2.App.overlay_componentremoved — useextra_app_wrapsto inject an overlay component.rx.Modeldefault primary key override: defining your own primary key no longer silently drops the built-inidfield. If you need custom PKs on a registered SQLModel class, register it via@rx.ModelRegistry.registerand declare the table explicitly.MutableProxykeys inState.get_value(...)are no longer accepted — pass astrkey.codeblockinrx.markdowncomponent_mapremoved — usepreinstead to customize code-block rendering.'string-name'entries indisable_pluginsare still supported in 0.9.0 but now targeted for removal in 1.0 (passPluginclasses directly, e.g.disable_plugins=[SitemapPlugin]).RouterData.pagedeprecation has been pushed out to 1.0 — still works in 0.9.0, useRouterData.urlgoing forward.
What's Changed
- provide event for redis state expiry by @adhami3310 in #6194
- Support FunctionVar handlers in EventChain rendering by @FarhanAliRaza in #6188
- feat: add chunked file upload support Streaming Upload API (rx.upload_files_chunk) by @FarhanAliRaza in #6190
- Add in-memory state expiration to StateManagerMemory by @FarhanAliRaza in #6201
- feat: add experimental memo decorator for JS-level component and function memoization by @FarhanAliRaza in #6192
- Add chunked upload documentation for rx.upload_files_chunk by @FarhanAliRaza in #6259
- add sitemap slash configuration by @adhami3310 in #6291
- Add Defs to recharts components by @Darksinian in #6322
- Added dropdown-cell support for the data editor by @IEC1 in #6139
- feat: add backend_path config to prefix backend routes by @FarhanAliRaza in #6338
- ENG-9350: App.modify_state can directly modify SharedState tokens by @masenf in #6336
Performance Improvements
- fix: avoid eagerly copying uploaded files into memory by @FarhanAliRaza in #6174
- Cache expensive introspection calls in pyi_generator for faster stub generation by @FarhanAliRaza in #6187
- do inspect signature once by @adhami3310 in #6197
- define _compile_stateful_components as an external by @adhami3310 in #6198
- do not compile stateful components in dev mode by @adhami3310 in #6199
- skip duplicate DynamicRouteVar by @adhami3310 in #6202
- avoid validating app when running in backend only by @adhami3310 in #6203
Bugfixes
- Fix race conditions in StateManagerRedis lock detection by @masenf in #6196
- reflex.event: revert future annotation changes by @masenf in #6254
- Fix buffered upload handler not cancelling on client disconnect by @FarhanAliRaza in #6307
- fix: set_focus/blur_focus args stripped by get_handler_args for stateless handlers by @FarhanAliRaza in #6314
- Serve _upload files with content-disposition: attachment by @masenf in #6303
- fix: collect imports from components in props in _get_all_imports() by @lawrence3699 in #6317
- Remove last pydantic.v1 vestiage by @masenf in #6321
- Fix outstanding frontend_path issues by @masenf in #6328
- ENG-9348: Lifespan tasks execute in registration order by @masenf in #6334
- Expose
.importable_pathon the value returned from rx.asset by @masenf in #6348
Docs
- implement reflex docgen by @adhami3310 in #6200
- ENG-9032: move framework docs into framework repo by @adhami3310 in #6206
- Expose docs through reflex docgen by @adhami3310 in #6257
- make reflex state import dynamic by @adhami3310 in #6258
- remove all pcweb references from the docs by @adhami3310 in #6263
- add back images for readme by @adhami3310 in #6265
- Fix cond typing by @adhami3310 in #6279
- Make reflex init and docs uv-first by @GautamBytes in #6287
- Add docs app by @carlosabadia in #6299
- Add reflex-ui and integrations docs to packages by @carlosabadia in #6302
- Update docs sidebar text color by @carlosabadia in #6309
- Update posthog script by @carlosabadia in #6315
- Add posthog recordings and events by @carlosabadia in #6310
- Remove image zoom in how reflex works doc by @carlosabadia in #6276
- update reflex ui links by @carlosabadia in #6326
- ENG-9295: add docs llms.txt by @adhami3310 in #6327
- Update hugeicon import in reflex-ui by @carlosabadia in #6333
Chores
- 090dev by @adhami3310 in #6182
- README.md: Add responsive logo for light and dark themes by @masenf in #6253
- export modules for plugins by @adhami3310 in #6261
- make the ci better at not install reflex deps for reflex-web by @adhami3310 in #6262
- reflex core is typed by @adhami3310 in #6271
- Add wildcard ignore and pragma: no cover for compat shims by @masenf in #6275
- ENG-9277: Add AI builder, Entreprise and hosting docs by @carlosabadia in #6277
- Rename reflex core to reflex base by @adhami3310 in #6281
- specify directories for publish by @adhami3310 in #6282
- improve pypi directory handling by @adhami3310 in #6283
- publish dist star by @adhami3310 in #6284
- Codspeed benchmark for backend state event processing by @masenf in #6290
- Remove 090 deprecations by @adhami3310 in #6292
- Exclude old-style imports when they will be replaced with subpackage imports by @masenf in #6294
- ENG-9212: integration socket.dev in OSS integration tests by @masenf in #6280
- Bump requests from 2.32.5 to 2.33.0 in the uv group across 1 directory by @dependabot[bot] in #6251
- reflex-web CI uses local reflex version by @masenf in #6298
- remove git https pyproject by @adhami3310 in #6306
- remove flexdown completely by @adhami3310 in #6308
- Update some reflex ui components by @carlosabadia in #6311
- Add page whitelist instructions to README for faster docs app dev builds by @carlosabadia in #6313
- pyi_generator regression tests by @masenf in #6318
- More pyi_generator tweaks by @masenf in #6319
- Usability improvements for generated type hints by @masenf in #6300
- delete js prod command by @adhami3310 in #6323
- Add AGENTS.md by @masenf in #6337
- Bump locked dependencies for 0.9.0 by @masenf in #6329
- update DECORATED_PAGES type annotation by @zoumingzhe in #6266
New Contributors
- @FarhanAliRaza made their first contribution in #6174
- @GautamBytes made their first contribution in #6287
- @lawrence3699 made their first contribution in #6317
- @Darksinian made their first contribution in #6322
- @IEC1 made their first contribution in #6139
- @zoumingzhe made their first contribution in #6266
Full Changelog: v0.8.28...v0.9.0