github reflex-dev/reflex reflex-base-v0.9.9a1
reflex-base@0.9.9a1

latest releases: reflex-components-core-v0.9.9a1, v0.9.9a1, reflex-components-code-v0.9.4a1...
pre-release5 hours ago

Breaking Changes

  • get_config(reload=True) has been replaced by reload_config(), and the module-level bundled_libraries list in reflex_base.components.dynamic has moved onto the active RegistrationContext (use bundle_library() / reset_bundled_libraries() as before). (#6382)
  • pydantic is no longer a hard dependency; pydantic model support activates when it is installed. Use the reflex-base[pydantic] extra (or reflex[db]) to keep it. (#6786)
  • Upgraded the frontend to React Router 8.3.0 (from 7.18.2). Its new baseline requires Node 22.22.0+, so Node.MIN_VERSION moves from 22.12.0 to 22.22.0; the already-pinned React 19.2.8 and Vite 8.0.16 satisfy the React 19.2.7+ and Vite 7+ floors. React Router 8 dropped the react-router-dom re-export package, so it is no longer installed: components that declare library = "react-router-dom" must import from react-router instead (RouterProvider/HydratedRouter come from react-router/dom). Existing projects have the stale entry pruned from package.json on the next install. (#6854)

Deprecations

  • The console.debug/info/success/log/warn/error/timing helpers are deprecated (removal in 1.0) but keep working as shims; use logging.getLogger(__name__) and the pipeline in reflex_base.utils.log instead. The interactive Rich features (print/rule/status/ask/progress) remain first-class. (#6867)

Features

  • RegistrationContext now carries the loaded Config, the registered App, decorated pages, and bundled libraries, and provides fork() to derive a fresh context that preserves existing registrations while resetting the app and config. (#6382)
  • Validate incoming state deltas in the frontend before dispatching and report unprocessable updates to the backend via a new client_error socket event instead of failing silently in the browser console. Values reported by a client are escaped and bounded before reaching the backend logs. (#6827)
  • Added reflex_base.utils.log: a standard python logging pipeline with a rich-rendering console handler (legacy colors preserved), a JSON-lines handler behind REFLEX_LOG_JSON, record deduplication, and file logging. LogLevel gained a correct total ordering and to_logging_level(), and the interactive console helpers (print/rule/status/progress) now respect JSON mode. (#6863)
  • The compiled frontend now names what React DevTools shows. Every memoized component carries a displayName taken from the Python component class or @rx.memo function it was generated from, instead of rendering as Anonymous; every generated context (ColorModeContext, UploadFilesContext, DispatchContext, EventLoopContext, ThemeContext, and one per state) is named, so the provider stack reads as StateContext(reflex___state____state.my_state).Provider rather than an unlabelled Context.Provider; each page is labelled with its route (Component(blog/[slug])) instead of a bare Component; and client-only (NoSSRComponent) wrappers render as ClientSide(<Tag>). (#6945)
  • Add the REFLEX_REFERRER_PARAM environment variable, read at compile time to append a ref query parameter to the "Built with Reflex" badge link. (#6951)

Bug Fixes

  • Event handlers marked with @rx.event(supersedes=True) now use latest-wins semantics: enqueuing a new invocation cancels the previous unfinished event chain for the same client token. on_load_internal uses this to cancel stale on_load chains on navigation. (#6593)
  • @rx.memo functions that forward props through rx.RestProp now classify those props the same way a regular component does: a forwarded prop that is not a declared prop of the target (e.g. font_weight=) joins the component's style and renders as css, instead of being passed through as an unrecognized prop and silently dropped. Such props merge with an explicit style= rather than replacing it, and props the target actually declares are still forwarded normally. (#6605)
  • Declare rx.plugins.RadixThemesPlugin() in the rxconfig.py written by reflex init, so freshly scaffolded apps no longer emit the implicit Radix Themes enablement deprecation warning. (#6776)
  • Qualify annotations whose bare builtin name is shadowed by a member of the same class, so Var.create is no longer inferred as LiteralBooleanVar for every argument type. Var.bool, BaseComponent.set and PropsBase.dict shadowed bool, set and dict for annotations elsewhere in their own class bodies, which type checkers resolve against the class namespace. (#6846)
  • The vite preview server that react-router prerendering fetches pages from is now pinned to 127.0.0.1, fixing reflex export failing with Prerender: Request failed for /: ECONNREFUSED in environments where localhost resolves to both IPv4 and IPv6 loopback addresses (such as docker containers). (#6857)
  • Resolve event handler annotations before runtime state-class patches can shadow builtin names on Python 3.14. (#6890)
  • Chained events (those yielded by an event handler) now inherit the routing data of the event being processed, so router and dynamic route args resolve against the view that produced them instead of whichever view the last client-sent event left on the root state. (#6919)
  • Stop background event handlers from computing a delta and cleaning the root state after the state lock is dropped. On a shared state tree (opportunistic locking, in-memory state manager) that unlocked snapshot-then-clean raced concurrent foreground handlers: a write landing between the background task's dirty-var snapshot and its _clean() was silently discarded and never reached any delta. Background state changes are emitted by their async with self context exits, which hold the lock. (#6920)
  • Resolve TypeAliasType annotations (PEP 695 type statements and the typing_extensions backport) to their underlying value in Var.guess_type, so state vars annotated with an alias like type Key = Literal["day", "week"] compile instead of raising TypeError: Unsupported type ... for guess_type. Parameterized generic aliases (Keys[str] for type Keys[T] = list[T]) and aliases nested in unions (Key | None) are resolved as well. (#6944)

Performance

  • Dev mode no longer pays for React's per-element owner-stack capture: navigation clicks in a large app dropped from ~350ms to ~83ms of main-thread CPU (5.6x prod down to ~1.3x). In exchange React.captureOwnerStack() returns no owner frames in dev, which affects React DevTools' owner-stack view and custom error overlays built on that API; set REFLEX_REACT_OWNER_STACKS=1 to restore them. (#6905)
  • MemoComponent instances no longer opt out of compiler auto-memoization wholesale. Only the passthrough wrappers the auto-memoize pass generates do, tracked by the new auto_memo_wrapper flag on MemoComponentDefinition, so state-bound props and event handlers on a @rx.memo call site compile their hooks into a generated wrapper instead of the enclosing page. (#6949)

Miscellaneous

  • Removed the postcss entry from PackageJson.OVERRIDES, leaving that mapping empty. postcss is pinned directly in DEV_DEPENDENCIES (8.5.23), and a top-level pin already satisfies and dedupes every transitive requirer (autoprefixer, postcss-import, and vite's own ^8.5.15), so the override resolved to the same single copy while being strictly harder to retire: framework overrides are merged into a project's reflex.lock/package.json and never removed from it, so an override cannot be undone by a later Reflex release. Projects that already installed 0.9.8 keep an inert "postcss": "8.5.23" override in reflex.lock/package.json; it matches the dev-dependency pin and can be deleted by hand. (#6854)
  • Bump bundled vite from 8.0.16 to 8.2.0. The full-integration-suite memo regression that previously held the pin back was root-caused to a REFLEX_ENV_MODE=prod leak between AppHarness instances (fixed in reflex.testing), not to a vite defect. (#6857)
  • Internal logging in reflex-base migrated from the legacy console helpers to standard python logging per-module loggers. (#6864)
  • Property docstrings are now noun phrases rather than "Get the ..." / "Return the ..." (ruff 0.16's new D421). chain_updates() declares its events parameter as Any, matching the runtime validation it delegates to. Field.default, Field.default_factory, and Field.default_value() now admit None: a field whose annotated type has no computed default is given a None default and has its recorded annotation widened to match, so the static types were previously understating what these can hold. Internally, ImportVar and unionize are imported from the modules that define them instead of by way of reflex_base.vars.base, and two dead is not None guards were dropped from _isinstance() and the dependency-tracking bytecode scanner. (#6893)

Don't miss a new reflex release

NewReleases is sending notifications on new releases.