From 4bb5b75550e8d279c59528cc43cd1ba047f65995 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 5 Oct 2026 19:28:51 +0000
Subject: [PATCH 01/25] Materialize changelogs for reflex@0.10.0a1,
reflex-base@0.10.0a1, reflex-components-code@0.10.0a1,
reflex-components-gridjs@0.10.0a1, reflex-components-markdown@0.10.0a1,
reflex-components-moment@0.10.0a1, reflex-components-plotly@0.10.0a1,
reflex-components-radix@0.10.0a1, reflex-components-recharts@0.10.0a1,
reflex-docgen@0.10.0a1 (new-prerelease-minor)
---
CHANGELOG.md | 53 +++++++++++++++++++
news/+drop-dead-bun-options.misc.md | 1 -
news/+envvar-durations.feature.md | 1 -
news/+field-descriptors.breaking.md | 1 -
news/+field-descriptors.performance.md | 1 -
news/+first-load-hydrate.performance.md | 1 -
news/+hatch-build-editable.bugfix.md | 1 -
news/+inherited-var-proxy.bugfix.md | 1 -
news/+json-output-capture.bugfix.md | 1 -
news/+lifespan-task-cancel-log.bugfix.md | 1 -
news/+memo-body-analysis.performance.md | 1 -
news/+oplock-subscriber-race.bugfix.md | 1 -
news/+package-json-sync-cache.bugfix.md | 1 -
news/+refresh-dependencies.misc.md | 1 -
news/+router-url-self-query-param.bugfix.md | 1 -
news/+runtime-hot-paths.performance.md | 1 -
.../+shared-state-fanout-guard.performance.md | 1 -
news/+toast-action-docs.docs.md | 1 -
news/+unpicklable-redis-state.bugfix.md | 1 -
news/6425.breaking.md | 1 -
news/6706.bugfix.md | 1 -
news/6996.bugfix.md | 1 -
news/7093.bugfix.md | 1 -
news/7179.feature.md | 1 -
news/7210.bugfix.md | 1 -
news/7227.bugfix.md | 1 -
news/7259.bugfix.md | 1 -
news/7286.bugfix.md | 1 -
news/7317.bugfix.md | 1 -
news/7318.bugfix.md | 1 -
news/7322.bugfix.md | 1 -
news/7328.bugfix.md | 1 -
news/7348.bugfix.md | 1 -
packages/reflex-base/CHANGELOG.md | 49 +++++++++++++++++
.../news/+buffered-upload-txid.bugfix.md | 1 -
...cation-location-synthetic-frames.bugfix.md | 1 -
.../+download-var-data-encoding.bugfix.md | 1 -
.../+envvar-duration-deprecations.feature.md | 1 -
.../news/+envvar-timedelta-usages.feature.md | 1 -
.../+event-callback-fixed-arity.bugfix.md | 1 -
.../news/+field-descriptors.breaking.md | 1 -
.../news/+field-descriptors.feature.md | 1 -
.../news/+first-load-hydrate.performance.md | 1 -
.../news/+json-output-capture.feature.md | 1 -
.../news/+memo-body-analysis.performance.md | 1 -
.../news/+refresh-dependencies.misc.md | 1 -
.../news/+runtime-hot-paths.performance.md | 1 -
...+state-var-type-check-depth.performance.md | 1 -
.../news/+stream-late-deltas.bugfix.md | 1 -
.../news/+var-build-hot-paths.performance.md | 1 -
.../news/+var-slice-negative-step.bugfix.md | 1 -
.../reflex-base/news/+workflow-logger.misc.md | 1 -
packages/reflex-base/news/6425.breaking.md | 1 -
packages/reflex-base/news/6553.breaking.md | 1 -
packages/reflex-base/news/6996.misc.md | 1 -
packages/reflex-base/news/7004.bugfix.md | 1 -
packages/reflex-base/news/7053.performance.md | 1 -
packages/reflex-base/news/7179.feature.md | 1 -
packages/reflex-base/news/7208.feature.md | 1 -
packages/reflex-base/news/7227.bugfix.md | 1 -
packages/reflex-base/news/7256.bugfix.md | 1 -
packages/reflex-base/news/7319.bugfix.md | 1 -
packages/reflex-base/news/7339.bugfix.md | 1 -
packages/reflex-base/news/7358.bugfix.md | 1 -
packages/reflex-base/news/7369.bugfix.md | 1 -
packages/reflex-components-code/CHANGELOG.md | 7 +++
.../news/+refresh-dependencies.misc.md | 1 -
.../reflex-components-gridjs/CHANGELOG.md | 7 +++
.../news/+base-minimum.bugfix.md | 1 -
.../reflex-components-markdown/CHANGELOG.md | 7 +++
.../news/+base-minimum.bugfix.md | 1 -
.../reflex-components-moment/CHANGELOG.md | 7 +++
.../news/+refresh-dependencies.misc.md | 1 -
.../reflex-components-plotly/CHANGELOG.md | 7 +++
.../news/7226.bugfix.md | 1 -
packages/reflex-components-radix/CHANGELOG.md | 11 ++++
.../news/+base-minimum.bugfix.md | 1 -
.../news/+refresh-dependencies.misc.md | 1 -
.../reflex-components-recharts/CHANGELOG.md | 8 +++
.../news/+base-minimum.bugfix.md | 1 -
.../news/7366.bugfix.md | 1 -
packages/reflex-docgen/CHANGELOG.md | 7 +++
.../news/+frontmatter-boundaries.bugfix.md | 1 -
83 files changed, 163 insertions(+), 73 deletions(-)
delete mode 100644 news/+drop-dead-bun-options.misc.md
delete mode 100644 news/+envvar-durations.feature.md
delete mode 100644 news/+field-descriptors.breaking.md
delete mode 100644 news/+field-descriptors.performance.md
delete mode 100644 news/+first-load-hydrate.performance.md
delete mode 100644 news/+hatch-build-editable.bugfix.md
delete mode 100644 news/+inherited-var-proxy.bugfix.md
delete mode 100644 news/+json-output-capture.bugfix.md
delete mode 100644 news/+lifespan-task-cancel-log.bugfix.md
delete mode 100644 news/+memo-body-analysis.performance.md
delete mode 100644 news/+oplock-subscriber-race.bugfix.md
delete mode 100644 news/+package-json-sync-cache.bugfix.md
delete mode 100644 news/+refresh-dependencies.misc.md
delete mode 100644 news/+router-url-self-query-param.bugfix.md
delete mode 100644 news/+runtime-hot-paths.performance.md
delete mode 100644 news/+shared-state-fanout-guard.performance.md
delete mode 100644 news/+toast-action-docs.docs.md
delete mode 100644 news/+unpicklable-redis-state.bugfix.md
delete mode 100644 news/6425.breaking.md
delete mode 100644 news/6706.bugfix.md
delete mode 100644 news/6996.bugfix.md
delete mode 100644 news/7093.bugfix.md
delete mode 100644 news/7179.feature.md
delete mode 100644 news/7210.bugfix.md
delete mode 100644 news/7227.bugfix.md
delete mode 100644 news/7259.bugfix.md
delete mode 100644 news/7286.bugfix.md
delete mode 100644 news/7317.bugfix.md
delete mode 100644 news/7318.bugfix.md
delete mode 100644 news/7322.bugfix.md
delete mode 100644 news/7328.bugfix.md
delete mode 100644 news/7348.bugfix.md
delete mode 100644 packages/reflex-base/news/+buffered-upload-txid.bugfix.md
delete mode 100644 packages/reflex-base/news/+deprecation-location-synthetic-frames.bugfix.md
delete mode 100644 packages/reflex-base/news/+download-var-data-encoding.bugfix.md
delete mode 100644 packages/reflex-base/news/+envvar-duration-deprecations.feature.md
delete mode 100644 packages/reflex-base/news/+envvar-timedelta-usages.feature.md
delete mode 100644 packages/reflex-base/news/+event-callback-fixed-arity.bugfix.md
delete mode 100644 packages/reflex-base/news/+field-descriptors.breaking.md
delete mode 100644 packages/reflex-base/news/+field-descriptors.feature.md
delete mode 100644 packages/reflex-base/news/+first-load-hydrate.performance.md
delete mode 100644 packages/reflex-base/news/+json-output-capture.feature.md
delete mode 100644 packages/reflex-base/news/+memo-body-analysis.performance.md
delete mode 100644 packages/reflex-base/news/+refresh-dependencies.misc.md
delete mode 100644 packages/reflex-base/news/+runtime-hot-paths.performance.md
delete mode 100644 packages/reflex-base/news/+state-var-type-check-depth.performance.md
delete mode 100644 packages/reflex-base/news/+stream-late-deltas.bugfix.md
delete mode 100644 packages/reflex-base/news/+var-build-hot-paths.performance.md
delete mode 100644 packages/reflex-base/news/+var-slice-negative-step.bugfix.md
delete mode 100644 packages/reflex-base/news/+workflow-logger.misc.md
delete mode 100644 packages/reflex-base/news/6425.breaking.md
delete mode 100644 packages/reflex-base/news/6553.breaking.md
delete mode 100644 packages/reflex-base/news/6996.misc.md
delete mode 100644 packages/reflex-base/news/7004.bugfix.md
delete mode 100644 packages/reflex-base/news/7053.performance.md
delete mode 100644 packages/reflex-base/news/7179.feature.md
delete mode 100644 packages/reflex-base/news/7208.feature.md
delete mode 100644 packages/reflex-base/news/7227.bugfix.md
delete mode 100644 packages/reflex-base/news/7256.bugfix.md
delete mode 100644 packages/reflex-base/news/7319.bugfix.md
delete mode 100644 packages/reflex-base/news/7339.bugfix.md
delete mode 100644 packages/reflex-base/news/7358.bugfix.md
delete mode 100644 packages/reflex-base/news/7369.bugfix.md
delete mode 100644 packages/reflex-components-code/news/+refresh-dependencies.misc.md
delete mode 100644 packages/reflex-components-gridjs/news/+base-minimum.bugfix.md
delete mode 100644 packages/reflex-components-markdown/news/+base-minimum.bugfix.md
delete mode 100644 packages/reflex-components-moment/news/+refresh-dependencies.misc.md
delete mode 100644 packages/reflex-components-plotly/news/7226.bugfix.md
delete mode 100644 packages/reflex-components-radix/news/+base-minimum.bugfix.md
delete mode 100644 packages/reflex-components-radix/news/+refresh-dependencies.misc.md
delete mode 100644 packages/reflex-components-recharts/news/+base-minimum.bugfix.md
delete mode 100644 packages/reflex-components-recharts/news/7366.bugfix.md
delete mode 100644 packages/reflex-docgen/news/+frontmatter-boundaries.bugfix.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5015bf7a920..39c6df15f43 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,56 @@
+## v0.10.0a1 (2026-10-05)
+
+### Breaking Changes
+
+- Remove the `reflex component` CLI (`init`, `build`, `share`, `install`) and the `CustomComponents` constants. Wrap React libraries directly in your app as described in the wrapping React docs, and start reusable component packages from the [component template](https://github.com/reflex-dev/component-template), which builds, tests, and publishes them with standard Python tooling. ([#6425](https://github.com/reflex-dev/reflex/issues/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 `BaseVarShadowsInheritedVarError` or `ComputedVarShadowsBaseVarsError`. A dynamic route arg only conflicts with a var of the state it is installed on. Assigning an undeclared state attribute still raises `SetUndefinedStateVarError` outside of prod mode, but no longer in prod. The internal class maps `backend_vars`, `inherited_vars` and `inherited_backend_vars`, `get_skip_vars()` and the instance `_backend_vars` are removed: use `get_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 (like `self._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](https://github.com/reflex-dev/reflex/issues/7312))
+
+### Features
+
+- The duration settings read by the app and the state managers take a unit suffix: `SQLALCHEMY_POOL_TIMEOUT`, `REFLEX_SOCKET_INTERVAL` and `REFLEX_SOCKET_TIMEOUT` accept values such as `2m`, and `REFLEX_AUTO_RELOAD_COOLDOWN`, `REFLEX_OPLOCK_HOLD_TIME` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE` replace the `_MS`/`_SECONDS` names, which still work with a deprecation warning until 1.0. A bare number is read as seconds. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
+- Set `REFLEX_REDIS_MAX_CONNECTIONS` to 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 to `REFLEX_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](https://github.com/reflex-dev/reflex/issues/7179))
+
+### Bug Fixes
+
+- Fixed `reflex db makemigrations`/`migrate` crashing with `CompileError` when autogenerating a migration that adds a column with a callable default (e.g. `default_factory=datetime.now` or `default=uuid.uuid4`) to an existing table; callable defaults are now evaluated before being carried as a SQL `server_default`. ([#6706](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/6996))
+- When a project keeps using npm because `reflex.lock/` only has `package-lock.json` (for example after a run with `REFLEX_USE_NPM=1`), Reflex now logs why and how to switch back to bun with `REFLEX_USE_NPM=0`. ([#7093](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7210))
+- Preserve ID-based form controls through automatic memoization while excluding IDs on non-controls from submissions. ([#7227](https://github.com/reflex-dev/reflex/issues/7227))
+- Avoid reinstalling frontend packages on every compile or hot reload when bun or npm only changes the formatting of `package.json`. ([#7236](https://github.com/reflex-dev/reflex/issues/7236))
+- `reflex db` commands run without the `db` extra installed now exit with the "pip install reflex[db]" message instead of a raw traceback. ([#7259](https://github.com/reflex-dev/reflex/issues/7259))
+- Fix `TypeError: refs._client_state_set... is not a function` when a component sets a global `rx._x.client_state` value before any component reading `.value` has mounted, such as when the reader sits behind an `rx.cond`. ([#7286](https://github.com/reflex-dev/reflex/issues/7286))
+- An editable install (`uv sync`, `pip install -e .`) no longer overwrites `.pyi` stubs that the checkout already has. A checkout missing any of them still gets them generated. ([#7303](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7312))
+- Fix stylesheet edits in `assets/` not applying in dev mode until a manual reload. The global stylesheet `` is now emitted only in production builds, so Vite's CSS hot update swaps the real stylesheet link again. ([#7317](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7318))
+- `reflex db` commands only require `sqlalchemy` and `alembic`, so apps that use plain SQLAlchemy models without `sqlmodel` can run migrations again. ([#7322](https://github.com/reflex-dev/reflex/issues/7322))
+- A page URL with a `self` query parameter (e.g. `/post?self=1`), or a request header named `self`, no longer crashes router data parsing and leaves the page unhydrated. ([#7324](https://github.com/reflex-dev/reflex/issues/7324))
+- `reflex run` now 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](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7348))
+- `reflex run --json` now emits every output line as a JSON record: `print()` output from the app, subprocess output, and worker tracebacks (as one record with an `exception` field) no longer break the JSON-lines stream. ([#7350](https://github.com/reflex-dev/reflex/issues/7350))
+- Fix a race with `REFLEX_OPLOCK_ENABLED` where 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](https://github.com/reflex-dev/reflex/issues/7372))
+- Stop logging `asyncio.CancelledError: lifespan_cleanup` as an error when a running coroutine lifespan task is cancelled at backend shutdown or hot reload. ([#7392](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7064))
+- Reuse unchanged memo-body analysis during module emission to reduce repeated rendering and artifact collection. ([#7123](https://github.com/reflex-dev/reflex/issues/7123))
+- Skip the linked-client fan-out on events that changed nothing shared, so an app that defines an `rx.SharedState` no longer resolves the running `App` on every event. ([#7237](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7370))
+
+### Documentation
+
+- Document the dict form for `rx.toast` `action` and `cancel` props instead of referencing the non-public `ToastAction` class. ([#7327](https://github.com/reflex-dev/reflex/issues/7327))
+
+### Miscellaneous
+
+- No longer set `BUN_OPTIONS` when launching the frontend dev server; bun ignores it for the process it spawns for a package script. ([#7203](https://github.com/reflex-dev/reflex/issues/7203))
+- Allow wrapt 2.4 and 2.5, and keep SQLModel below 0.0.45 to preserve existing datetime storage behavior. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
+
+
## v0.9.12 (2026-09-21)
### Breaking Changes
diff --git a/news/+drop-dead-bun-options.misc.md b/news/+drop-dead-bun-options.misc.md
deleted file mode 100644
index 982c1e419a9..00000000000
--- a/news/+drop-dead-bun-options.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-No longer set `BUN_OPTIONS` when launching the frontend dev server; bun ignores it for the process it spawns for a package script.
diff --git a/news/+envvar-durations.feature.md b/news/+envvar-durations.feature.md
deleted file mode 100644
index 74b29d738f0..00000000000
--- a/news/+envvar-durations.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-The duration settings read by the app and the state managers take a unit suffix: `SQLALCHEMY_POOL_TIMEOUT`, `REFLEX_SOCKET_INTERVAL` and `REFLEX_SOCKET_TIMEOUT` accept values such as `2m`, and `REFLEX_AUTO_RELOAD_COOLDOWN`, `REFLEX_OPLOCK_HOLD_TIME` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE` replace the `_MS`/`_SECONDS` names, which still work with a deprecation warning until 1.0. A bare number is read as seconds.
diff --git a/news/+field-descriptors.breaking.md b/news/+field-descriptors.breaking.md
deleted file mode 100644
index 8b27841d9c3..00000000000
--- a/news/+field-descriptors.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-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 `BaseVarShadowsInheritedVarError` or `ComputedVarShadowsBaseVarsError`. A dynamic route arg only conflicts with a var of the state it is installed on. Assigning an undeclared state attribute still raises `SetUndefinedStateVarError` outside of prod mode, but no longer in prod. The internal class maps `backend_vars`, `inherited_vars` and `inherited_backend_vars`, `get_skip_vars()` and the instance `_backend_vars` are removed: use `get_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 (like `self._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.
diff --git a/news/+field-descriptors.performance.md b/news/+field-descriptors.performance.md
deleted file mode 100644
index a411df5f7f2..00000000000
--- a/news/+field-descriptors.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-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__`.
diff --git a/news/+first-load-hydrate.performance.md b/news/+first-load-hydrate.performance.md
deleted file mode 100644
index 5a034a31790..00000000000
--- a/news/+first-load-hydrate.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/news/+hatch-build-editable.bugfix.md b/news/+hatch-build-editable.bugfix.md
deleted file mode 100644
index 4f0cfb0fcc8..00000000000
--- a/news/+hatch-build-editable.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-An editable install (`uv sync`, `pip install -e .`) no longer overwrites `.pyi` stubs that the checkout already has. A checkout missing any of them still gets them generated.
diff --git a/news/+inherited-var-proxy.bugfix.md b/news/+inherited-var-proxy.bugfix.md
deleted file mode 100644
index c29ed63e131..00000000000
--- a/news/+inherited-var-proxy.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/news/+json-output-capture.bugfix.md b/news/+json-output-capture.bugfix.md
deleted file mode 100644
index 7bbfbb7d7c5..00000000000
--- a/news/+json-output-capture.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex run --json` now emits every output line as a JSON record: `print()` output from the app, subprocess output, and worker tracebacks (as one record with an `exception` field) no longer break the JSON-lines stream.
diff --git a/news/+lifespan-task-cancel-log.bugfix.md b/news/+lifespan-task-cancel-log.bugfix.md
deleted file mode 100644
index c62a1238026..00000000000
--- a/news/+lifespan-task-cancel-log.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Stop logging `asyncio.CancelledError: lifespan_cleanup` as an error when a running coroutine lifespan task is cancelled at backend shutdown or hot reload.
diff --git a/news/+memo-body-analysis.performance.md b/news/+memo-body-analysis.performance.md
deleted file mode 100644
index 8bd47d5e26a..00000000000
--- a/news/+memo-body-analysis.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-Reuse unchanged memo-body analysis during module emission to reduce repeated rendering and artifact collection.
diff --git a/news/+oplock-subscriber-race.bugfix.md b/news/+oplock-subscriber-race.bugfix.md
deleted file mode 100644
index 45b7854b57a..00000000000
--- a/news/+oplock-subscriber-race.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Fix a race with `REFLEX_OPLOCK_ENABLED` where 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.
diff --git a/news/+package-json-sync-cache.bugfix.md b/news/+package-json-sync-cache.bugfix.md
deleted file mode 100644
index f6509d1b217..00000000000
--- a/news/+package-json-sync-cache.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Avoid reinstalling frontend packages on every compile or hot reload when bun or npm only changes the formatting of `package.json`.
diff --git a/news/+refresh-dependencies.misc.md b/news/+refresh-dependencies.misc.md
deleted file mode 100644
index 748ffb50b99..00000000000
--- a/news/+refresh-dependencies.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Allow wrapt 2.4 and 2.5, and keep SQLModel below 0.0.45 to preserve existing datetime storage behavior.
diff --git a/news/+router-url-self-query-param.bugfix.md b/news/+router-url-self-query-param.bugfix.md
deleted file mode 100644
index 050ec346c1c..00000000000
--- a/news/+router-url-self-query-param.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-A page URL with a `self` query parameter (e.g. `/post?self=1`), or a request header named `self`, no longer crashes router data parsing and leaves the page unhydrated.
diff --git a/news/+runtime-hot-paths.performance.md b/news/+runtime-hot-paths.performance.md
deleted file mode 100644
index afe7d5704d2..00000000000
--- a/news/+runtime-hot-paths.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/news/+shared-state-fanout-guard.performance.md b/news/+shared-state-fanout-guard.performance.md
deleted file mode 100644
index 952ec40acb1..00000000000
--- a/news/+shared-state-fanout-guard.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-Skip the linked-client fan-out on events that changed nothing shared, so an app that defines an `rx.SharedState` no longer resolves the running `App` on every event.
diff --git a/news/+toast-action-docs.docs.md b/news/+toast-action-docs.docs.md
deleted file mode 100644
index 8c5a6bb1399..00000000000
--- a/news/+toast-action-docs.docs.md
+++ /dev/null
@@ -1 +0,0 @@
-Document the dict form for `rx.toast` `action` and `cancel` props instead of referencing the non-public `ToastAction` class.
diff --git a/news/+unpicklable-redis-state.bugfix.md b/news/+unpicklable-redis-state.bugfix.md
deleted file mode 100644
index 3549ab6b190..00000000000
--- a/news/+unpicklable-redis-state.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/news/6425.breaking.md b/news/6425.breaking.md
deleted file mode 100644
index 669d0710584..00000000000
--- a/news/6425.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Remove the `reflex component` CLI (`init`, `build`, `share`, `install`) and the `CustomComponents` constants. Wrap React libraries directly in your app as described in the wrapping React docs, and start reusable component packages from the [component template](https://github.com/reflex-dev/component-template), which builds, tests, and publishes them with standard Python tooling.
diff --git a/news/6706.bugfix.md b/news/6706.bugfix.md
deleted file mode 100644
index 415e5bd6509..00000000000
--- a/news/6706.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Fixed `reflex db makemigrations`/`migrate` crashing with `CompileError` when autogenerating a migration that adds a column with a callable default (e.g. `default_factory=datetime.now` or `default=uuid.uuid4`) to an existing table; callable defaults are now evaluated before being carried as a SQL `server_default`.
diff --git a/news/6996.bugfix.md b/news/6996.bugfix.md
deleted file mode 100644
index 82eb53a9953..00000000000
--- a/news/6996.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/news/7093.bugfix.md b/news/7093.bugfix.md
deleted file mode 100644
index 38c1af0e65f..00000000000
--- a/news/7093.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-When a project keeps using npm because `reflex.lock/` only has `package-lock.json` (for example after a run with `REFLEX_USE_NPM=1`), Reflex now logs why and how to switch back to bun with `REFLEX_USE_NPM=0`.
diff --git a/news/7179.feature.md b/news/7179.feature.md
deleted file mode 100644
index 11da100d7d2..00000000000
--- a/news/7179.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-Set `REFLEX_REDIS_MAX_CONNECTIONS` to 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 to `REFLEX_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.
diff --git a/news/7210.bugfix.md b/news/7210.bugfix.md
deleted file mode 100644
index bed8412595b..00000000000
--- a/news/7210.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/news/7227.bugfix.md b/news/7227.bugfix.md
deleted file mode 100644
index 86a92076cd7..00000000000
--- a/news/7227.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Preserve ID-based form controls through automatic memoization while excluding IDs on non-controls from submissions.
diff --git a/news/7259.bugfix.md b/news/7259.bugfix.md
deleted file mode 100644
index f30af353e1b..00000000000
--- a/news/7259.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex db` commands run without the `db` extra installed now exit with the "pip install reflex[db]" message instead of a raw traceback.
diff --git a/news/7286.bugfix.md b/news/7286.bugfix.md
deleted file mode 100644
index 7dcbd78b918..00000000000
--- a/news/7286.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Fix `TypeError: refs._client_state_set... is not a function` when a component sets a global `rx._x.client_state` value before any component reading `.value` has mounted, such as when the reader sits behind an `rx.cond`.
diff --git a/news/7317.bugfix.md b/news/7317.bugfix.md
deleted file mode 100644
index c9c05a4ed9f..00000000000
--- a/news/7317.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Fix stylesheet edits in `assets/` not applying in dev mode until a manual reload. The global stylesheet `` is now emitted only in production builds, so Vite's CSS hot update swaps the real stylesheet link again.
diff --git a/news/7318.bugfix.md b/news/7318.bugfix.md
deleted file mode 100644
index 0e698cc112e..00000000000
--- a/news/7318.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/news/7322.bugfix.md b/news/7322.bugfix.md
deleted file mode 100644
index c6a905dceb3..00000000000
--- a/news/7322.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex db` commands only require `sqlalchemy` and `alembic`, so apps that use plain SQLAlchemy models without `sqlmodel` can run migrations again.
diff --git a/news/7328.bugfix.md b/news/7328.bugfix.md
deleted file mode 100644
index 8c5e419ee8c..00000000000
--- a/news/7328.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex run` now 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.
diff --git a/news/7348.bugfix.md b/news/7348.bugfix.md
deleted file mode 100644
index 57ffa7a0821..00000000000
--- a/news/7348.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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]`.
diff --git a/packages/reflex-base/CHANGELOG.md b/packages/reflex-base/CHANGELOG.md
index a58e4b91ec2..fac1123608d 100644
--- a/packages/reflex-base/CHANGELOG.md
+++ b/packages/reflex-base/CHANGELOG.md
@@ -1,3 +1,52 @@
+## v0.10.0a1 (2026-10-05)
+
+### Breaking Changes
+
+- Remove `reflex_base.constants.CustomComponents`, which only the removed `reflex component` CLI used. ([#6425](https://github.com/reflex-dev/reflex/issues/6425))
+- `PageContext.get()` and `CompileContext.get()` now raise `LookupError` instead of `RuntimeError` when no context is active, the same as every other `BaseContext` subclass. Compiler plugins that catch `RuntimeError` around these calls should catch `LookupError`. ([#6553](https://github.com/reflex-dev/reflex/issues/6553))
+- `reflex_base.utils.types.is_backend_base_variable` and `RESERVED_BACKEND_VAR_NAMES` are removed: whether a state var is a backend var is now a property of its `Field` in `get_fields()`. By convention, fields named with a leading `_` are backend vars. `is_mutable_type` moved to `reflex_base.utils.types` (still importable from `reflex.istate.proxy`). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
+
+### Features
+
+- `SQLALCHEMY_POOL_TIMEOUT`, `REFLEX_BACKEND_COLD_START_TIMEOUT`, `REFLEX_SOCKET_INTERVAL` and `REFLEX_SOCKET_TIMEOUT` are `timedelta` settings, so they accept a unit suffix such as `REFLEX_SOCKET_TIMEOUT=2m`. A bare number is still read as seconds, so existing values keep their meaning. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
+- `REFLEX_AUTO_RELOAD_COOLDOWN`, `REFLEX_OPLOCK_HOLD_TIME` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE` replace `REFLEX_AUTO_RELOAD_COOLDOWN_TIME_MS`, `REFLEX_OPLOCK_HOLD_TIME_MS` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE_SECONDS`, and take a duration such as `250ms` or `5m`. The old names still work and keep counting the unit in their name, with a deprecation warning; they are removed in 1.0. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
+- Add the `REFLEX_REDIS_MAX_CONNECTIONS` and `REFLEX_REDIS_POOL_TIMEOUT` environment 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](https://github.com/reflex-dev/reflex/issues/7179))
+- Add `Var.deep_equals()` for structural comparison of nested frontend values. ([#7208](https://github.com/reflex-dev/reflex/issues/7208))
+- `Field` is now the descriptor holding a state var's value, and `EventHandler` binds to the state that declares it when accessed on a state instance. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
+- 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](https://github.com/reflex-dev/reflex/issues/7350))
+
+### Bug Fixes
+
+- Auto-memoized `@rx.memo` wrapper names no longer repeat the wrapped memo component's tag. ([#7004](https://github.com/reflex-dev/reflex/issues/7004))
+- Deprecation warnings no longer point at a pseudo-location such as `` or `` when the deprecated call runs inside generated or frozen code; the location now names the first real user file. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
+- Form submissions retain ID-backed controls with unset values while omitting IDs from non-controls. ([#7227](https://github.com/reflex-dev/reflex/issues/7227))
+- `Var._replace(_var_data=...)` no longer raises `TypeError: dataclasses.replace() got multiple values for keyword argument '_var_data'`. ([#7256](https://github.com/reflex-dev/reflex/issues/7256))
+- Flatten nested client event lists before dispatch and keep processing queued events after one event fails. ([#7319](https://github.com/reflex-dev/reflex/issues/7319))
+- `rx.download(data=State.var)` percent-encodes the JSON it puts in the `data:` URL, so a `#` or `%` in the data no longer truncates or corrupts the downloaded file. ([#7325](https://github.com/reflex-dev/reflex/issues/7325))
+- Negative-step slices of array and string Vars now match Python at a `-1` bound (e.g. `State.items[-1::-1]` no longer renders an empty list), and a Var step (e.g. `State.items[::State.step]`) no longer raises `RecursionError`. ([#7326](https://github.com/reflex-dev/reflex/issues/7326))
+- A state that mixes in `abc.ABC` or another `ABCMeta` class (`class MyMixin(ABC, rx.State, mixin=True)`) no longer fails with a `StateValueError` claiming `_abc_impl` is reserved by `BaseState`. ([#7339](https://github.com/reflex-dev/reflex/issues/7339))
+- Events sent while a buffered upload (or another `EventProcessor.enqueue_stream_delta` stream) 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_load` handlers again. Concurrent buffered uploads no longer hang or end each other's responses early. ([#7357](https://github.com/reflex-dev/reflex/issues/7357))
+- State changes made after a buffered 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](https://github.com/reflex-dev/reflex/issues/7357))
+- 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 a `reflex.event.parent_txid` naming the event processor's root context; only chained events name the event that produced them. ([#7358](https://github.com/reflex-dev/reflex/issues/7358))
+- 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](https://github.com/reflex-dev/reflex/issues/7369))
+- 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](https://github.com/reflex-dev/reflex/issues/7414))
+
+### Performance
+
+- Reduce event-queue overhead when prepending events and processing events with a connected socket. ([#7053](https://github.com/reflex-dev/reflex/issues/7053))
+- Begin opening the websocket transport before React mounts, then hydrate with a single `hydrate_and_load` event sent along with the websocket connect to save a round trip. ([#7064](https://github.com/reflex-dev/reflex/issues/7064))
+- Evaluate generated passthrough memo bodies once and retain their render and artifacts so module emission does not repeat the work. ([#7123](https://github.com/reflex-dev/reflex/issues/7123))
+- 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](https://github.com/reflex-dev/reflex/issues/7353))
+- 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](https://github.com/reflex-dev/reflex/issues/7370))
+- 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_background` and `EventHandler.supersedes` are read once per handler, so mark the function before the handler is first used. ([#7370](https://github.com/reflex-dev/reflex/issues/7370))
+
+### Miscellaneous
+
+- Add the `routes.json` manifest name constant, written at compile time so the prod static file server can tell routable SPA paths from unknown ones. ([#6996](https://github.com/reflex-dev/reflex/issues/6996))
+- Route log records from the new `reflex-workflow` package through the Reflex logger, so they follow the configured log level and sinks. ([#7288](https://github.com/reflex-dev/reflex/issues/7288))
+- 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](https://github.com/reflex-dev/reflex/issues/7424))
+
+
## v0.9.12 (2026-09-21)
### Features
diff --git a/packages/reflex-base/news/+buffered-upload-txid.bugfix.md b/packages/reflex-base/news/+buffered-upload-txid.bugfix.md
deleted file mode 100644
index abb058d6e5c..00000000000
--- a/packages/reflex-base/news/+buffered-upload-txid.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Events sent while a buffered upload (or another `EventProcessor.enqueue_stream_delta` stream) 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_load` handlers again. Concurrent buffered uploads no longer hang or end each other's responses early.
diff --git a/packages/reflex-base/news/+deprecation-location-synthetic-frames.bugfix.md b/packages/reflex-base/news/+deprecation-location-synthetic-frames.bugfix.md
deleted file mode 100644
index 016ca5f9ca7..00000000000
--- a/packages/reflex-base/news/+deprecation-location-synthetic-frames.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Deprecation warnings no longer point at a pseudo-location such as `` or `` when the deprecated call runs inside generated or frozen code; the location now names the first real user file.
diff --git a/packages/reflex-base/news/+download-var-data-encoding.bugfix.md b/packages/reflex-base/news/+download-var-data-encoding.bugfix.md
deleted file mode 100644
index a43aa87cd72..00000000000
--- a/packages/reflex-base/news/+download-var-data-encoding.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`rx.download(data=State.var)` percent-encodes the JSON it puts in the `data:` URL, so a `#` or `%` in the data no longer truncates or corrupts the downloaded file.
diff --git a/packages/reflex-base/news/+envvar-duration-deprecations.feature.md b/packages/reflex-base/news/+envvar-duration-deprecations.feature.md
deleted file mode 100644
index 21343b77093..00000000000
--- a/packages/reflex-base/news/+envvar-duration-deprecations.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-`REFLEX_AUTO_RELOAD_COOLDOWN`, `REFLEX_OPLOCK_HOLD_TIME` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE` replace `REFLEX_AUTO_RELOAD_COOLDOWN_TIME_MS`, `REFLEX_OPLOCK_HOLD_TIME_MS` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE_SECONDS`, and take a duration such as `250ms` or `5m`. The old names still work and keep counting the unit in their name, with a deprecation warning; they are removed in 1.0.
diff --git a/packages/reflex-base/news/+envvar-timedelta-usages.feature.md b/packages/reflex-base/news/+envvar-timedelta-usages.feature.md
deleted file mode 100644
index b8107bf36a7..00000000000
--- a/packages/reflex-base/news/+envvar-timedelta-usages.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-`SQLALCHEMY_POOL_TIMEOUT`, `REFLEX_BACKEND_COLD_START_TIMEOUT`, `REFLEX_SOCKET_INTERVAL` and `REFLEX_SOCKET_TIMEOUT` are `timedelta` settings, so they accept a unit suffix such as `REFLEX_SOCKET_TIMEOUT=2m`. A bare number is still read as seconds, so existing values keep their meaning.
diff --git a/packages/reflex-base/news/+event-callback-fixed-arity.bugfix.md b/packages/reflex-base/news/+event-callback-fixed-arity.bugfix.md
deleted file mode 100644
index aa8ad7e5acd..00000000000
--- a/packages/reflex-base/news/+event-callback-fixed-arity.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/packages/reflex-base/news/+field-descriptors.breaking.md b/packages/reflex-base/news/+field-descriptors.breaking.md
deleted file mode 100644
index 0fd0778990c..00000000000
--- a/packages/reflex-base/news/+field-descriptors.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex_base.utils.types.is_backend_base_variable` and `RESERVED_BACKEND_VAR_NAMES` are removed: whether a state var is a backend var is now a property of its `Field` in `get_fields()`. By convention, fields named with a leading `_` are backend vars. `is_mutable_type` moved to `reflex_base.utils.types` (still importable from `reflex.istate.proxy`).
diff --git a/packages/reflex-base/news/+field-descriptors.feature.md b/packages/reflex-base/news/+field-descriptors.feature.md
deleted file mode 100644
index b052d462e50..00000000000
--- a/packages/reflex-base/news/+field-descriptors.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-`Field` is now the descriptor holding a state var's value, and `EventHandler` binds to the state that declares it when accessed on a state instance.
diff --git a/packages/reflex-base/news/+first-load-hydrate.performance.md b/packages/reflex-base/news/+first-load-hydrate.performance.md
deleted file mode 100644
index cb3e8a81216..00000000000
--- a/packages/reflex-base/news/+first-load-hydrate.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-Begin opening the websocket transport before React mounts, then hydrate with a single `hydrate_and_load` event sent along with the websocket connect to save a round trip.
diff --git a/packages/reflex-base/news/+json-output-capture.feature.md b/packages/reflex-base/news/+json-output-capture.feature.md
deleted file mode 100644
index 59d162fce4c..00000000000
--- a/packages/reflex-base/news/+json-output-capture.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/packages/reflex-base/news/+memo-body-analysis.performance.md b/packages/reflex-base/news/+memo-body-analysis.performance.md
deleted file mode 100644
index c1862b92ca8..00000000000
--- a/packages/reflex-base/news/+memo-body-analysis.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-Evaluate generated passthrough memo bodies once and retain their render and artifacts so module emission does not repeat the work.
diff --git a/packages/reflex-base/news/+refresh-dependencies.misc.md b/packages/reflex-base/news/+refresh-dependencies.misc.md
deleted file mode 100644
index b616b23a86c..00000000000
--- a/packages/reflex-base/news/+refresh-dependencies.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/packages/reflex-base/news/+runtime-hot-paths.performance.md b/packages/reflex-base/news/+runtime-hot-paths.performance.md
deleted file mode 100644
index 624c91e28c9..00000000000
--- a/packages/reflex-base/news/+runtime-hot-paths.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-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_background` and `EventHandler.supersedes` are read once per handler, so mark the function before the handler is first used.
diff --git a/packages/reflex-base/news/+state-var-type-check-depth.performance.md b/packages/reflex-base/news/+state-var-type-check-depth.performance.md
deleted file mode 100644
index 0da75491ad2..00000000000
--- a/packages/reflex-base/news/+state-var-type-check-depth.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/packages/reflex-base/news/+stream-late-deltas.bugfix.md b/packages/reflex-base/news/+stream-late-deltas.bugfix.md
deleted file mode 100644
index 63381c3e31e..00000000000
--- a/packages/reflex-base/news/+stream-late-deltas.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-State changes made after a buffered 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.
diff --git a/packages/reflex-base/news/+var-build-hot-paths.performance.md b/packages/reflex-base/news/+var-build-hot-paths.performance.md
deleted file mode 100644
index 4b50f0233cd..00000000000
--- a/packages/reflex-base/news/+var-build-hot-paths.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-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.
diff --git a/packages/reflex-base/news/+var-slice-negative-step.bugfix.md b/packages/reflex-base/news/+var-slice-negative-step.bugfix.md
deleted file mode 100644
index 99e29e7fc4f..00000000000
--- a/packages/reflex-base/news/+var-slice-negative-step.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Negative-step slices of array and string Vars now match Python at a `-1` bound (e.g. `State.items[-1::-1]` no longer renders an empty list), and a Var step (e.g. `State.items[::State.step]`) no longer raises `RecursionError`.
diff --git a/packages/reflex-base/news/+workflow-logger.misc.md b/packages/reflex-base/news/+workflow-logger.misc.md
deleted file mode 100644
index 300e2325e5e..00000000000
--- a/packages/reflex-base/news/+workflow-logger.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Route log records from the new `reflex-workflow` package through the Reflex logger, so they follow the configured log level and sinks.
diff --git a/packages/reflex-base/news/6425.breaking.md b/packages/reflex-base/news/6425.breaking.md
deleted file mode 100644
index afe8c1b57a4..00000000000
--- a/packages/reflex-base/news/6425.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Remove `reflex_base.constants.CustomComponents`, which only the removed `reflex component` CLI used.
diff --git a/packages/reflex-base/news/6553.breaking.md b/packages/reflex-base/news/6553.breaking.md
deleted file mode 100644
index bb38ee023ba..00000000000
--- a/packages/reflex-base/news/6553.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-`PageContext.get()` and `CompileContext.get()` now raise `LookupError` instead of `RuntimeError` when no context is active, the same as every other `BaseContext` subclass. Compiler plugins that catch `RuntimeError` around these calls should catch `LookupError`.
diff --git a/packages/reflex-base/news/6996.misc.md b/packages/reflex-base/news/6996.misc.md
deleted file mode 100644
index f9b153ab2c4..00000000000
--- a/packages/reflex-base/news/6996.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Add the `routes.json` manifest name constant, written at compile time so the prod static file server can tell routable SPA paths from unknown ones.
diff --git a/packages/reflex-base/news/7004.bugfix.md b/packages/reflex-base/news/7004.bugfix.md
deleted file mode 100644
index 61d7285e013..00000000000
--- a/packages/reflex-base/news/7004.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Auto-memoized `@rx.memo` wrapper names no longer repeat the wrapped memo component's tag.
diff --git a/packages/reflex-base/news/7053.performance.md b/packages/reflex-base/news/7053.performance.md
deleted file mode 100644
index f9910c39b44..00000000000
--- a/packages/reflex-base/news/7053.performance.md
+++ /dev/null
@@ -1 +0,0 @@
-Reduce event-queue overhead when prepending events and processing events with a connected socket.
diff --git a/packages/reflex-base/news/7179.feature.md b/packages/reflex-base/news/7179.feature.md
deleted file mode 100644
index 09aa8dd46a5..00000000000
--- a/packages/reflex-base/news/7179.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-Add the `REFLEX_REDIS_MAX_CONNECTIONS` and `REFLEX_REDIS_POOL_TIMEOUT` environment 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.
diff --git a/packages/reflex-base/news/7208.feature.md b/packages/reflex-base/news/7208.feature.md
deleted file mode 100644
index 0ba1fcd9bde..00000000000
--- a/packages/reflex-base/news/7208.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-Add `Var.deep_equals()` for structural comparison of nested frontend values.
diff --git a/packages/reflex-base/news/7227.bugfix.md b/packages/reflex-base/news/7227.bugfix.md
deleted file mode 100644
index 87756da2ac5..00000000000
--- a/packages/reflex-base/news/7227.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Form submissions retain ID-backed controls with unset values while omitting IDs from non-controls.
diff --git a/packages/reflex-base/news/7256.bugfix.md b/packages/reflex-base/news/7256.bugfix.md
deleted file mode 100644
index a81ac2877b6..00000000000
--- a/packages/reflex-base/news/7256.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`Var._replace(_var_data=...)` no longer raises `TypeError: dataclasses.replace() got multiple values for keyword argument '_var_data'`.
diff --git a/packages/reflex-base/news/7319.bugfix.md b/packages/reflex-base/news/7319.bugfix.md
deleted file mode 100644
index 10965a5d1e3..00000000000
--- a/packages/reflex-base/news/7319.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Flatten nested client event lists before dispatch and keep processing queued events after one event fails.
diff --git a/packages/reflex-base/news/7339.bugfix.md b/packages/reflex-base/news/7339.bugfix.md
deleted file mode 100644
index 7efdc09373a..00000000000
--- a/packages/reflex-base/news/7339.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-A state that mixes in `abc.ABC` or another `ABCMeta` class (`class MyMixin(ABC, rx.State, mixin=True)`) no longer fails with a `StateValueError` claiming `_abc_impl` is reserved by `BaseState`.
diff --git a/packages/reflex-base/news/7358.bugfix.md b/packages/reflex-base/news/7358.bugfix.md
deleted file mode 100644
index 44a288102d1..00000000000
--- a/packages/reflex-base/news/7358.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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 a `reflex.event.parent_txid` naming the event processor's root context; only chained events name the event that produced them.
diff --git a/packages/reflex-base/news/7369.bugfix.md b/packages/reflex-base/news/7369.bugfix.md
deleted file mode 100644
index 8a7668f630d..00000000000
--- a/packages/reflex-base/news/7369.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-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`.
diff --git a/packages/reflex-components-code/CHANGELOG.md b/packages/reflex-components-code/CHANGELOG.md
index 6fa7ff96c9b..81b4c746fe6 100644
--- a/packages/reflex-components-code/CHANGELOG.md
+++ b/packages/reflex-components-code/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-05)
+
+### Miscellaneous
+
+- Update Shiki and its transformers to 4.5.0. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
+
+
## v0.9.6 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-code/news/+refresh-dependencies.misc.md b/packages/reflex-components-code/news/+refresh-dependencies.misc.md
deleted file mode 100644
index e998eecd6a5..00000000000
--- a/packages/reflex-components-code/news/+refresh-dependencies.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Update Shiki and its transformers to 4.5.0.
diff --git a/packages/reflex-components-gridjs/CHANGELOG.md b/packages/reflex-components-gridjs/CHANGELOG.md
index 61788d27e45..2e103837000 100644
--- a/packages/reflex-components-gridjs/CHANGELOG.md
+++ b/packages/reflex-components-gridjs/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-05)
+
+### Bug Fixes
+
+- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
+
+
## v0.9.2.post1 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-gridjs/news/+base-minimum.bugfix.md b/packages/reflex-components-gridjs/news/+base-minimum.bugfix.md
deleted file mode 100644
index 927fcb55d99..00000000000
--- a/packages/reflex-components-gridjs/news/+base-minimum.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Require reflex-base 0.9.12 or newer so all imported rendering APIs are available.
diff --git a/packages/reflex-components-markdown/CHANGELOG.md b/packages/reflex-components-markdown/CHANGELOG.md
index 979969b4ec6..ed2e4366ad4 100644
--- a/packages/reflex-components-markdown/CHANGELOG.md
+++ b/packages/reflex-components-markdown/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-05)
+
+### Bug Fixes
+
+- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
+
+
## v0.9.4.post1 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-markdown/news/+base-minimum.bugfix.md b/packages/reflex-components-markdown/news/+base-minimum.bugfix.md
deleted file mode 100644
index 927fcb55d99..00000000000
--- a/packages/reflex-components-markdown/news/+base-minimum.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Require reflex-base 0.9.12 or newer so all imported rendering APIs are available.
diff --git a/packages/reflex-components-moment/CHANGELOG.md b/packages/reflex-components-moment/CHANGELOG.md
index baa1c8e6c12..6e540d8779d 100644
--- a/packages/reflex-components-moment/CHANGELOG.md
+++ b/packages/reflex-components-moment/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-05)
+
+### Miscellaneous
+
+- Update Moment to 2.31.0, moment-timezone to 0.6.5, and moment-duration-format to 2.3.2. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
+
+
## v0.9.4 (2026-09-11)
### Breaking Changes
diff --git a/packages/reflex-components-moment/news/+refresh-dependencies.misc.md b/packages/reflex-components-moment/news/+refresh-dependencies.misc.md
deleted file mode 100644
index c71905cd0ef..00000000000
--- a/packages/reflex-components-moment/news/+refresh-dependencies.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Update Moment to 2.31.0, moment-timezone to 0.6.5, and moment-duration-format to 2.3.2.
diff --git a/packages/reflex-components-plotly/CHANGELOG.md b/packages/reflex-components-plotly/CHANGELOG.md
index 2f4cc916a0c..f9088f85aab 100644
--- a/packages/reflex-components-plotly/CHANGELOG.md
+++ b/packages/reflex-components-plotly/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-05)
+
+### Bug Fixes
+
+- Normalize string Plotly layout titles to the `{"title": {"text": "..."}}` format required by Plotly.js. ([#7226](https://github.com/reflex-dev/reflex/issues/7226))
+
+
## v0.9.7 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-plotly/news/7226.bugfix.md b/packages/reflex-components-plotly/news/7226.bugfix.md
deleted file mode 100644
index ec71be0d2d7..00000000000
--- a/packages/reflex-components-plotly/news/7226.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Normalize string Plotly layout titles to the `{"title": {"text": "..."}}` format required by Plotly.js.
diff --git a/packages/reflex-components-radix/CHANGELOG.md b/packages/reflex-components-radix/CHANGELOG.md
index d88f92b54d7..838444ae563 100644
--- a/packages/reflex-components-radix/CHANGELOG.md
+++ b/packages/reflex-components-radix/CHANGELOG.md
@@ -1,3 +1,14 @@
+## v0.10.0a1 (2026-10-05)
+
+### Bug Fixes
+
+- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
+
+### Miscellaneous
+
+- Update the Radix slider and progress dependencies to 1.4.7 and 1.1.16. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
+
+
## v0.9.10.post1 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-radix/news/+base-minimum.bugfix.md b/packages/reflex-components-radix/news/+base-minimum.bugfix.md
deleted file mode 100644
index 927fcb55d99..00000000000
--- a/packages/reflex-components-radix/news/+base-minimum.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Require reflex-base 0.9.12 or newer so all imported rendering APIs are available.
diff --git a/packages/reflex-components-radix/news/+refresh-dependencies.misc.md b/packages/reflex-components-radix/news/+refresh-dependencies.misc.md
deleted file mode 100644
index 238d0407852..00000000000
--- a/packages/reflex-components-radix/news/+refresh-dependencies.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Update the Radix slider and progress dependencies to 1.4.7 and 1.1.16.
diff --git a/packages/reflex-components-recharts/CHANGELOG.md b/packages/reflex-components-recharts/CHANGELOG.md
index 5c5e4ec2a52..b2fdf9e9027 100644
--- a/packages/reflex-components-recharts/CHANGELOG.md
+++ b/packages/reflex-components-recharts/CHANGELOG.md
@@ -1,3 +1,11 @@
+## v0.10.0a1 (2026-10-05)
+
+### Bug Fixes
+
+- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
+- Allow Recharts axis tick formatters to use Reflex function vars. ([#7366](https://github.com/reflex-dev/reflex/issues/7366))
+
+
## v0.9.4.post1 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-recharts/news/+base-minimum.bugfix.md b/packages/reflex-components-recharts/news/+base-minimum.bugfix.md
deleted file mode 100644
index 927fcb55d99..00000000000
--- a/packages/reflex-components-recharts/news/+base-minimum.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Require reflex-base 0.9.12 or newer so all imported rendering APIs are available.
diff --git a/packages/reflex-components-recharts/news/7366.bugfix.md b/packages/reflex-components-recharts/news/7366.bugfix.md
deleted file mode 100644
index c1158e357b8..00000000000
--- a/packages/reflex-components-recharts/news/7366.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Allow Recharts axis tick formatters to use Reflex function vars.
diff --git a/packages/reflex-docgen/CHANGELOG.md b/packages/reflex-docgen/CHANGELOG.md
index 7029aa4d108..08a184ebf46 100644
--- a/packages/reflex-docgen/CHANGELOG.md
+++ b/packages/reflex-docgen/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-05)
+
+### Bug Fixes
+
+- Recognize YAML frontmatter after a UTF-8 BOM or leading whitespace and with CRLF line endings, keeping metadata out of rendered page content and tables of contents. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
+
+
## v0.9.5 (2026-08-28)
### Miscellaneous
diff --git a/packages/reflex-docgen/news/+frontmatter-boundaries.bugfix.md b/packages/reflex-docgen/news/+frontmatter-boundaries.bugfix.md
deleted file mode 100644
index 0576792ed10..00000000000
--- a/packages/reflex-docgen/news/+frontmatter-boundaries.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Recognize YAML frontmatter after a UTF-8 BOM or leading whitespace and with CRLF line endings, keeping metadata out of rendered page content and tables of contents.
From 59c675abbf6ddc973770c28f9aab22fdde675848 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Mon, 5 Oct 2026 21:54:16 +0000
Subject: [PATCH 02/25] Materialize changelogs for
reflex-components-core@0.10.0a1 (new-prerelease-minor)
---
packages/reflex-components-core/CHANGELOG.md | 17 +++++++++++++++++
.../news/+base-minimum.bugfix.md | 1 -
.../news/+envvar-durations.feature.md | 1 -
.../news/+refresh-dependencies.misc.md | 1 -
.../reflex-components-core/news/6675.bugfix.md | 1 -
.../reflex-components-core/news/7227.bugfix.md | 1 -
packages/reflex-components-core/pyproject.toml | 2 +-
7 files changed, 18 insertions(+), 6 deletions(-)
delete mode 100644 packages/reflex-components-core/news/+base-minimum.bugfix.md
delete mode 100644 packages/reflex-components-core/news/+envvar-durations.feature.md
delete mode 100644 packages/reflex-components-core/news/+refresh-dependencies.misc.md
delete mode 100644 packages/reflex-components-core/news/6675.bugfix.md
delete mode 100644 packages/reflex-components-core/news/7227.bugfix.md
diff --git a/packages/reflex-components-core/CHANGELOG.md b/packages/reflex-components-core/CHANGELOG.md
index dc084d2f851..320472abbfd 100644
--- a/packages/reflex-components-core/CHANGELOG.md
+++ b/packages/reflex-components-core/CHANGELOG.md
@@ -1,3 +1,20 @@
+## v0.10.0a1 (2026-10-05)
+
+### Features
+
+- The connection banner reads `REFLEX_BACKEND_COLD_START_TIMEOUT` as a duration, so it accepts a unit suffix such as `30s`. A bare number is still read as seconds. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
+
+### Bug Fixes
+
+- Fix `rx.match` raising `ReferenceError: Can't find variable` at render when a state Var is used only in a case condition with component branches. ([#6675](https://github.com/reflex-dev/reflex/issues/6675))
+- Exclude IDs on forms and other non-controls from form submissions while preserving unset ID-backed controls and supporting custom controls marked with `_is_form_control`. ([#7227](https://github.com/reflex-dev/reflex/issues/7227))
+- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
+
+### Miscellaneous
+
+- Update react-dropzone to 17.0.0 and react-error-boundary to 6.1.6. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
+
+
## v0.9.10.post1 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-core/news/+base-minimum.bugfix.md b/packages/reflex-components-core/news/+base-minimum.bugfix.md
deleted file mode 100644
index 927fcb55d99..00000000000
--- a/packages/reflex-components-core/news/+base-minimum.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Require reflex-base 0.9.12 or newer so all imported rendering APIs are available.
diff --git a/packages/reflex-components-core/news/+envvar-durations.feature.md b/packages/reflex-components-core/news/+envvar-durations.feature.md
deleted file mode 100644
index f11f30094c1..00000000000
--- a/packages/reflex-components-core/news/+envvar-durations.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-The connection banner reads `REFLEX_BACKEND_COLD_START_TIMEOUT` as a duration, so it accepts a unit suffix such as `30s`. A bare number is still read as seconds.
diff --git a/packages/reflex-components-core/news/+refresh-dependencies.misc.md b/packages/reflex-components-core/news/+refresh-dependencies.misc.md
deleted file mode 100644
index 679fff566cf..00000000000
--- a/packages/reflex-components-core/news/+refresh-dependencies.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Update react-dropzone to 17.0.0 and react-error-boundary to 6.1.6.
diff --git a/packages/reflex-components-core/news/6675.bugfix.md b/packages/reflex-components-core/news/6675.bugfix.md
deleted file mode 100644
index ca2c199bb27..00000000000
--- a/packages/reflex-components-core/news/6675.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Fix `rx.match` raising `ReferenceError: Can't find variable` at render when a state Var is used only in a case condition with component branches.
diff --git a/packages/reflex-components-core/news/7227.bugfix.md b/packages/reflex-components-core/news/7227.bugfix.md
deleted file mode 100644
index 34b638c3524..00000000000
--- a/packages/reflex-components-core/news/7227.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Exclude IDs on forms and other non-controls from form submissions while preserving unset ID-backed controls and supporting custom controls marked with `_is_form_control`.
diff --git a/packages/reflex-components-core/pyproject.toml b/packages/reflex-components-core/pyproject.toml
index 9d8798b5b06..af03ccd9d97 100644
--- a/packages/reflex-components-core/pyproject.toml
+++ b/packages/reflex-components-core/pyproject.toml
@@ -8,7 +8,7 @@ authors = [{ name = "Khaleel Al-Adhami", email = "khaleel@reflex.dev" }]
maintainers = [{ name = "Khaleel Al-Adhami", email = "khaleel@reflex.dev" }]
requires-python = ">=3.10"
dependencies = [
- "reflex-base >= 0.9.12.post11.dev0",
+ "reflex-base >= 0.10.0a1",
"reflex-components-lucide >= 0.9.0",
"reflex-components-sonner >= 0.9.0",
"python_multipart >= 0.0.21",
From 23a3b6ec1c1f6df0ed339ef1264413f6967cd755 Mon Sep 17 00:00:00 2001
From: Claude
Date: Tue, 6 Oct 2026 18:15:09 +0000
Subject: [PATCH 03/25] Document class-level backend var access returning Field
as breaking
Since #7312 made Field the descriptor for state vars, reading a backend
var on the state class returns the Field instead of the default value.
Code that passed that default to a component now fails with
ChildrenTypeError or the LiteralVar TypeError. Add a Breaking Changes
entry to the 0.10.0a1 section with the migration via default_value().
Co-Authored-By: Claude Fable 5.1
Claude-Session: https://claude.ai/code/session_01R98baxdcSdivcfDYrqxqF6
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39c6df15f43..8877efb0692 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
- Remove the `reflex component` CLI (`init`, `build`, `share`, `install`) and the `CustomComponents` constants. Wrap React libraries directly in your app as described in the wrapping React docs, and start reusable component packages from the [component template](https://github.com/reflex-dev/component-template), which builds, tests, and publishes them with standard Python tooling. ([#6425](https://github.com/reflex-dev/reflex/issues/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 `BaseVarShadowsInheritedVarError` or `ComputedVarShadowsBaseVarsError`. A dynamic route arg only conflicts with a var of the state it is installed on. Assigning an undeclared state attribute still raises `SetUndefinedStateVarError` outside of prod mode, but no longer in prod. The internal class maps `backend_vars`, `inherited_vars` and `inherited_backend_vars`, `get_skip_vars()` and the instance `_backend_vars` are removed: use `get_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 (like `self._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](https://github.com/reflex-dev/reflex/issues/7312))
+- Reading a backend var on a state class (`State._items`) now returns its `Field` descriptor instead of the var's default value. Passing it to a component, which used to bake the default into the frontend, now raises `ChildrenTypeError` as a child or `TypeError: Unsupported type for LiteralVar.` as a prop. To keep baking in the default, pass `State._items.default_value()` instead; to make the value reactive, declare a frontend var or computed var and pass that. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
### Features
From bf12bd43f036b3f295db8baf4b1505ff08fe6e92 Mon Sep 17 00:00:00 2001
From: Masen Furer
Date: Tue, 6 Oct 2026 21:45:17 -0700
Subject: [PATCH 04/25] Prepare Python 3.11 floors and phased 0.10 prereleases
(#7464)
* Prepare Python 3.11 floors and directional prerelease phases
* Simplify directional lockstep planning
A publish-last member now needs only the early members of its group,
tagged at its own version: it plans from its own baseline, reuses a
sibling tag that already exists, and otherwise plans the sibling at the
same version. Early members release on their own. Two publish-last
members no longer need each other, so pin-exact groups with several
cannot deadlock on each other's tags.
Planning computes targets first and checks the dependency pins of what
it planned, holding back blocked packages and the packages that need
them; an explicit selection that cannot release fails as before. The
exact pin is checked against the declared requirement at plan time as
well as at build time, so a floor raised past a reusable sibling tag
stops the release before any changelog is bumped. prepare-publish
requires every early member's tag before a publish-last member builds.
Sibling floors use the .dev0 of each sibling's next version, and the
docs, template comments and news fragments say the same thing in fewer
words.
Co-Authored-By: Claude Fable 5.1
Claude-Session: https://claude.ai/code/session_01MZxGmMwCvKGcUJu6TK99jZ
* Hold back blocked packages before planning their versions
The planner skips a package with an unsatisfiable pin instead of
computing its next version, so a release action that does not apply to
a held dependent no longer stops its sibling's release. Blocked pins are
gathered once for the selection and its lockstep partners; a dependent
whose missing partner is blocked is held back with it, and a partner
reused from an existing tag is not consulted at all.
Co-Authored-By: Claude Fable 5.1
Claude-Session: https://claude.ai/code/session_01MZxGmMwCvKGcUJu6TK99jZ
* Delete packages/reflex-hosting-cli/news/+sdk-minor-compatibility.misc.md
* Say which tags the publish-last leg waits for
The workflow comment described the late leg as waiting on every package
in the batch; it runs after the first leg, but the gate is the tags of
the siblings each late member pins.
Co-Authored-By: Claude Fable 5.1
Claude-Session: https://claude.ai/code/session_01MZxGmMwCvKGcUJu6TK99jZ
---------
Co-authored-by: Claude
---
.github/workflows/dispatch_release.yml | 12 +-
.github/workflows/release_from_changelog.yml | 6 +-
CONTRIBUTING.md | 13 +-
news/+python311-sibling-floors.misc.md | 1 +
.../reflex-components-code/pyproject.toml | 8 +-
.../reflex-components-core/pyproject.toml | 6 +-
.../pyproject.toml | 4 +-
.../reflex-components-gridjs/pyproject.toml | 2 +-
.../reflex-components-lucide/pyproject.toml | 2 +-
.../reflex-components-markdown/pyproject.toml | 8 +-
.../reflex-components-moment/pyproject.toml | 2 +-
.../reflex-components-plotly/pyproject.toml | 4 +-
.../reflex-components-radix/pyproject.toml | 6 +-
.../pyproject.toml | 4 +-
.../reflex-components-recharts/pyproject.toml | 4 +-
.../reflex-components-sonner/pyproject.toml | 4 +-
packages/reflex-docgen/pyproject.toml | 2 +-
packages/reflex-hosting-cli/pyproject.toml | 9 +-
packages/reflex-release/README.md | 70 ++--
.../news/+directional-lockstep.feature.md | 1 +
.../src/reflex_release/commands.py | 182 ++++++----
.../src/reflex_release/config.py | 31 +-
.../reflex-release/src/reflex_release/dist.py | 37 +-
.../src/reflex_release/scaffold.py | 15 +-
.../templates/workflows/dispatch_release.yml | 3 +-
.../workflows/release_from_changelog.yml | 6 +-
pyproject.toml | 33 +-
tests/units/reflex_release/conftest.py | 8 +-
tests/units/reflex_release/test_commands.py | 322 +++++++++++++++++-
tests/units/reflex_release/test_config.py | 28 +-
tests/units/reflex_release/test_dist.py | 18 +
tests/units/reflex_release/test_scaffold.py | 20 +-
tests/units/test_check_min_deps.py | 21 +-
33 files changed, 699 insertions(+), 193 deletions(-)
create mode 100644 news/+python311-sibling-floors.misc.md
create mode 100644 packages/reflex-release/news/+directional-lockstep.feature.md
diff --git a/.github/workflows/dispatch_release.yml b/.github/workflows/dispatch_release.yml
index b04b5358a6c..65f3826c84c 100644
--- a/.github/workflows/dispatch_release.yml
+++ b/.github/workflows/dispatch_release.yml
@@ -12,7 +12,8 @@ name: Dispatch release
# Selecting no package auto-selects the ones to release: those with pending
# news fragments — or, for release-from-prerelease, those whose changelog is
# topped by an alpha (the train's fragments are already consumed). Lockstep
-# groups share one checkbox: their members only ever release together.
+# groups without publish-last share one checkbox: their members only ever
+# release together. With publish-last, each member has its own.
#
# Materializing also lifts each released package's unshippable dependency
# floors — a *.dev pin, and a prerelease pin when the version is final — to the
@@ -75,13 +76,17 @@ on:
- release-minor
- release-major
reflex:
- description: "reflex (with reflex-base)"
+ description: "reflex"
type: boolean
default: false
hatch_reflex_pyi:
description: "hatch-reflex-pyi"
type: boolean
default: false
+ reflex_base:
+ description: "reflex-base"
+ type: boolean
+ default: false
reflex_build_sdk:
description: "reflex-build-sdk"
type: boolean
@@ -186,8 +191,9 @@ jobs:
# Each unselected package contributes an empty string, so selecting
# nothing leaves PACKAGES blank and the planner auto-selects.
PACKAGES: >-
- ${{ inputs.reflex && 'reflex,reflex-base' || '' }}
+ ${{ inputs.reflex && 'reflex' || '' }}
${{ inputs.hatch_reflex_pyi && 'hatch-reflex-pyi' || '' }}
+ ${{ inputs.reflex_base && 'reflex-base' || '' }}
${{ inputs.reflex_build_sdk && 'reflex-build-sdk' || '' }}
${{ inputs.reflex_components_code && 'reflex-components-code' || '' }}
${{ inputs.reflex_components_core && 'reflex-components-core' || '' }}
diff --git a/.github/workflows/release_from_changelog.yml b/.github/workflows/release_from_changelog.yml
index c785df88cc4..51d1c7e70ae 100644
--- a/.github/workflows/release_from_changelog.yml
+++ b/.github/workflows/release_from_changelog.yml
@@ -19,9 +19,9 @@ name: Release from changelog
# r/pre-* or r/hotfix/** (the Dispatch release workflow
# materializes alphas on r/pre-* branches).
#
-# Lockstep packages that pin their siblings exactly publish strictly after
-# every other package in the batch; detect fails closed if a lockstep
-# invariant is broken.
+# Lockstep packages that pin their siblings exactly publish in a second leg,
+# after the rest of the batch, and only once the siblings they pin are tagged;
+# detect fails closed if a lockstep invariant is broken.
#
# workflow_dispatch exists so the Dispatch release workflow can trigger a
# check on a branch it just pushed (pushes made with GITHUB_TOKEN do not fire
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ba479d91623..477ebcdaef3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -115,16 +115,17 @@ a release branch — never by tagging manually. The pieces:
`release-from-prerelease` collapses the accumulated alpha sections into
one final-version section — alpha headings never ship in a final
changelog.
- - `reflex` and `reflex-base` are a lockstep pair and share one checkbox:
- selecting it releases both at the same version. The checkboxes are
- generated from the package list, so adding or removing a package means
- re-running `uv run reflex-release sync`.
+ - `reflex` and `reflex-base` are a lockstep pair with separate checkboxes:
+ `reflex-base` releases on its own, while `reflex` needs `reflex-base`
+ tagged at the same version — reusing an existing tag or releasing base
+ alongside. The checkboxes are generated from the package list, so adding
+ or removing a package means re-running `uv run reflex-release sync`.
2. **Release from changelog** (`release_from_changelog.yml`) runs on every push
to `main`, `r/pre-*`, and `r/hotfix/**`: any package whose newest changelog
version has no git tag gets built and queued for publishing. Final
(non-alpha) versions only publish from `main` or `r/hotfix/**`; alphas only
- from `r/pre-*`/`r/hotfix/**`. `reflex` and `reflex-base` are checked as a
- lockstep pair and `reflex` publishes only after the rest of the batch.
+ from `r/pre-*`/`r/hotfix/**`. `reflex` publishes only after the rest of the
+ batch, once its `reflex-base` tag exists.
3. **Publish to PyPI** (`publish.yml`, also manually dispatchable with a
package + version) validates and builds without privileges, then **waits
for a human to approve the `pypi` environment deployment** — every upload,
diff --git a/news/+python311-sibling-floors.misc.md b/news/+python311-sibling-floors.misc.md
new file mode 100644
index 00000000000..68a6cb67b61
--- /dev/null
+++ b/news/+python311-sibling-floors.misc.md
@@ -0,0 +1 @@
+Require sibling package versions from the Python 3.11 release train.
diff --git a/packages/reflex-components-code/pyproject.toml b/packages/reflex-components-code/pyproject.toml
index a214a457fa0..fad8c019c48 100644
--- a/packages/reflex-components-code/pyproject.toml
+++ b/packages/reflex-components-code/pyproject.toml
@@ -16,10 +16,10 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.9.0",
- "reflex-components-core >= 0.9.0",
- "reflex-components-lucide >= 0.9.0",
- "reflex-components-radix >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-core >= 0.10.0a2.dev0",
+ "reflex-components-lucide >= 1.0.5.dev0",
+ "reflex-components-radix >= 0.10.0a2.dev0",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-core/pyproject.toml b/packages/reflex-components-core/pyproject.toml
index 7d3899a8c0f..084c125aa48 100644
--- a/packages/reflex-components-core/pyproject.toml
+++ b/packages/reflex-components-core/pyproject.toml
@@ -16,9 +16,9 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a1",
- "reflex-components-lucide >= 0.9.0",
- "reflex-components-sonner >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-lucide >= 1.0.5.dev0",
+ "reflex-components-sonner >= 0.9.5.dev0",
"python_multipart >= 0.0.21",
"starlette >= 0.47.0",
"typing_extensions >= 4.0.0",
diff --git a/packages/reflex-components-dataeditor/pyproject.toml b/packages/reflex-components-dataeditor/pyproject.toml
index 6a206b24321..d13eb7fdb16 100644
--- a/packages/reflex-components-dataeditor/pyproject.toml
+++ b/packages/reflex-components-dataeditor/pyproject.toml
@@ -16,8 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.9.12",
- "reflex-components-core >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-core >= 0.10.0a2.dev0",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-gridjs/pyproject.toml b/packages/reflex-components-gridjs/pyproject.toml
index ea94590afc9..1694f726e28 100644
--- a/packages/reflex-components-gridjs/pyproject.toml
+++ b/packages/reflex-components-gridjs/pyproject.toml
@@ -15,7 +15,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
]
-dependencies = ["reflex-base >= 0.9.12"]
+dependencies = ["reflex-base >= 0.10.0a2.dev0"]
[tool.hatch.version]
source = "uv-dynamic-versioning"
diff --git a/packages/reflex-components-lucide/pyproject.toml b/packages/reflex-components-lucide/pyproject.toml
index 5c8c0310525..de7695063a1 100644
--- a/packages/reflex-components-lucide/pyproject.toml
+++ b/packages/reflex-components-lucide/pyproject.toml
@@ -15,7 +15,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
]
-dependencies = ["reflex-base >= 0.9.0"]
+dependencies = ["reflex-base >= 0.10.0a2.dev0"]
[tool.hatch.version]
source = "uv-dynamic-versioning"
diff --git a/packages/reflex-components-markdown/pyproject.toml b/packages/reflex-components-markdown/pyproject.toml
index aaffc4039ff..83f5802c699 100644
--- a/packages/reflex-components-markdown/pyproject.toml
+++ b/packages/reflex-components-markdown/pyproject.toml
@@ -16,10 +16,10 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.9.12",
- "reflex-components-code >= 0.9.0",
- "reflex-components-core >= 0.9.0",
- "reflex-components-radix >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-code >= 0.10.0a2.dev0",
+ "reflex-components-core >= 0.10.0a2.dev0",
+ "reflex-components-radix >= 0.10.0a2.dev0",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-moment/pyproject.toml b/packages/reflex-components-moment/pyproject.toml
index 04d1ac910c5..1763599bb26 100644
--- a/packages/reflex-components-moment/pyproject.toml
+++ b/packages/reflex-components-moment/pyproject.toml
@@ -15,7 +15,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
]
-dependencies = ["reflex-base >= 0.9.0"]
+dependencies = ["reflex-base >= 0.10.0a2.dev0"]
[tool.hatch.version]
source = "uv-dynamic-versioning"
diff --git a/packages/reflex-components-plotly/pyproject.toml b/packages/reflex-components-plotly/pyproject.toml
index 97a4c2bc7d6..8c4205fdc43 100644
--- a/packages/reflex-components-plotly/pyproject.toml
+++ b/packages/reflex-components-plotly/pyproject.toml
@@ -18,8 +18,8 @@ classifiers = [
dependencies = [
# The unversioned "mergician" import resolves against the pin in
# reflex-base's PackageJson.DEPENDENCIES.
- "reflex-base >= 0.9.12",
- "reflex-components-core >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-core >= 0.10.0a2.dev0",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-radix/pyproject.toml b/packages/reflex-components-radix/pyproject.toml
index 48cc4d44ce3..9269e536fa5 100644
--- a/packages/reflex-components-radix/pyproject.toml
+++ b/packages/reflex-components-radix/pyproject.toml
@@ -16,9 +16,9 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.9.12",
- "reflex-components-core >= 0.9.5",
- "reflex-components-lucide >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-core >= 0.10.0a2.dev0",
+ "reflex-components-lucide >= 1.0.5.dev0",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-react-player/pyproject.toml b/packages/reflex-components-react-player/pyproject.toml
index 2aae5a31716..0b5a30aa63b 100644
--- a/packages/reflex-components-react-player/pyproject.toml
+++ b/packages/reflex-components-react-player/pyproject.toml
@@ -16,8 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.9.0",
- "reflex-components-core >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-core >= 0.10.0a2.dev0",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-recharts/pyproject.toml b/packages/reflex-components-recharts/pyproject.toml
index 1ad2799a5c3..e6d03269478 100644
--- a/packages/reflex-components-recharts/pyproject.toml
+++ b/packages/reflex-components-recharts/pyproject.toml
@@ -16,8 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.9.12",
- "reflex-components-core >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-core >= 0.10.0a2.dev0",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-sonner/pyproject.toml b/packages/reflex-components-sonner/pyproject.toml
index 02ec2728ec9..8f75e1e6232 100644
--- a/packages/reflex-components-sonner/pyproject.toml
+++ b/packages/reflex-components-sonner/pyproject.toml
@@ -16,8 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.9.0",
- "reflex-components-lucide >= 0.9.0",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-lucide >= 1.0.5.dev0",
]
[tool.hatch.version]
diff --git a/packages/reflex-docgen/pyproject.toml b/packages/reflex-docgen/pyproject.toml
index 00499741588..7ff21af1134 100644
--- a/packages/reflex-docgen/pyproject.toml
+++ b/packages/reflex-docgen/pyproject.toml
@@ -19,7 +19,7 @@ dependencies = [
"griffelib >= 2.0.1",
"mistletoe >= 1.4.0",
"pyyaml >= 6.0.3",
- "reflex >= 0.9.0",
+ "reflex >= 0.10.0a2.dev0",
"typing-inspection>=0.4.2",
]
diff --git a/packages/reflex-hosting-cli/pyproject.toml b/packages/reflex-hosting-cli/pyproject.toml
index 795aff96c3f..8dbada456db 100644
--- a/packages/reflex-hosting-cli/pyproject.toml
+++ b/packages/reflex-hosting-cli/pyproject.toml
@@ -31,10 +31,11 @@ dependencies = [
# The SDK ships no HTTP library of its own; [httpx] points it at the one
# `check_version` already pulls in, so the extra costs nothing to install.
# The SDK is pre-1.0, so every release may break its API: cap at the patch
- # and raise all three bounds when adopting a new one. The workspace builds
- # the SDK as a dev release of the next patch (``0.0.6.devN``), which
- # ``<0.0.6`` would exclude; ``!=0.0.6`` keeps that release itself out.
- "reflex-build-sdk[httpx] >=0.0.5,<0.0.6.post,!=0.0.6",
+ # and raise all three bounds when adopting a new one. The floor admits the
+ # workspace's dev build until the 0.1.0 alpha publishes and materialization
+ # lifts it; the cap admits 0.1.0 and the ``0.1.1.devN`` builds that follow
+ # its tag, but not 0.1.1 itself.
+ "reflex-build-sdk[httpx] >=0.0.6.dev0,<0.1.1.post,!=0.1.1",
"rich >=13,<16",
]
diff --git a/packages/reflex-release/README.md b/packages/reflex-release/README.md
index b9f35e97987..598ee26e594 100644
--- a/packages/reflex-release/README.md
+++ b/packages/reflex-release/README.md
@@ -179,35 +179,54 @@ you called it) and the directory name under `packages/` for the rest.
### Lockstep packages
-Packages that must always release together at the same version — typically
-because one pins the other exactly — form a lockstep group:
+Packages that release at one version — typically because one pins the other
+exactly — form a lockstep group:
```toml
[[tool.reflex-release.lockstep]]
members = ["mypkg", "mypkg-base"]
-# Members that publish only after every other member is uploaded and tagged.
+# Members that publish only after the others are uploaded and tagged.
publish-last = ["mypkg"]
-# Rewrite each publish-last member's requirement on its siblings to
+# Rewrite each publish-last member's requirement on the others to
# "== " before building.
pin-exact = true
```
-This gives you, for free:
-
-- selecting one member in *Dispatch release* selects the whole group, and all
- members are planned at one version (the highest baseline among them);
-- `release_from_changelog` publishes `publish-last` members only after the rest
- of the batch succeeded — never shipping a wheel whose exact pin does not
- exist on PyPI yet;
-- a member with nothing to report still gets its section, holding towncrier's
- "No significant changes." placeholder — nobody hand-writes a changelog entry
- just to satisfy the invariant, and a member does not even need a `news/`
- directory;
-- detection **fails closed** if one member's changelog is bumped without the
- other's (re-dispatching a release fixes it, materializing the whole group).
+Without `publish-last`, the members only ever release together: they share one
+*Dispatch release* checkbox, selecting one selects all, their next version
+comes from the highest baseline among them, and an unsatisfiable dependency
+pin in one holds back the whole group.
+
+With `publish-last`, each member gets its own checkbox and the group is
+directional:
+
+- an early member (`mypkg-base`) releases on its own, from its own baseline;
+- a `publish-last` member (`mypkg`) advances from its own baseline and needs
+ every early member tagged at the new version. One already tagged there is
+ reused — after base publishes `1.2.0a2`, `mypkg` at `1.2.0a1` continues to
+ `1.2.0a2` on that release even if base has moved on since. Otherwise the
+ early member is planned at the same version, unless its changelog is already
+ past it, which stops the plan;
+- `release_from_changelog` publishes `publish-last` members after the rest of
+ the batch, and `prepare-publish` refuses to build one until every early
+ member's tag exists, so a manual publish dispatch cannot run ahead either;
+- `publish-last` members do not need each other; each pins the early members
+ only.
+
+This is what dependency-first phases rest on: publish base, wait for its tag,
+then the packages that need it, and the dependent last. Each phase lifts its
+`.dev` floors to the versions tagged by the phases before it.
+
+In either kind of group, a member dragged in by its sibling still gets its
+changelog section, holding towncrier's "No significant changes." placeholder,
+and detection **fails closed** if a member's changelog is bumped without the
+siblings it needs being tagged or in the same batch.
`pin-exact` rewrites the requirement in the publishing package's
-`pyproject.toml` at build time only; it is never committed.
+`pyproject.toml` at build time only; it is never committed. The pinned version
+must satisfy the requirement as declared — planning and the build both check,
+so a floor raised past the sibling version a release would reuse stops it
+before anything is materialized.
### Dependency pins across a release
@@ -278,9 +297,9 @@ the lock.
A floor nothing published satisfies has nowhere to go, and the package is
**held back** rather than materialized into a version that could never be
-published — auto-selected packages are dropped from the batch (a lockstep group
-whole, since its members only release together) and listed in the run summary;
-an explicitly selected one fails the dispatch. Release the depended-on package
+published — auto-selected packages are dropped from the batch, together with
+the lockstep partners that need them, and listed in the run summary; an
+explicitly selected one fails the dispatch. Release the depended-on package
first and the next release lifts the pin by itself.
Two things are deliberately left alone: a floor on a lockstep sibling that
@@ -620,10 +639,11 @@ review-sensitive field.
## Cutting a release
Run **Dispatch release** from the Actions tab. Each package gets its own
-checkbox, generated from your configuration; a lockstep group gets a single
-checkbox covering all its members, since they only ever release together.
-Selecting nothing auto-selects: packages with pending news fragments, or — for
-`release-from-prerelease` — packages whose changelog is topped by an alpha.
+checkbox, generated from your configuration; a lockstep group without
+`publish-last` gets a single checkbox covering all its members, since they only
+ever release together. Selecting nothing auto-selects: packages with pending
+news fragments, or — for `release-from-prerelease` — packages whose changelog is
+topped by an alpha.
Because the checkboxes are generated, **adding or removing a package changes
`dispatch_release.yml`** — run `reflex-release sync` and commit it with the new
diff --git a/packages/reflex-release/news/+directional-lockstep.feature.md b/packages/reflex-release/news/+directional-lockstep.feature.md
new file mode 100644
index 00000000000..a928fe2f243
--- /dev/null
+++ b/packages/reflex-release/news/+directional-lockstep.feature.md
@@ -0,0 +1 @@
+Let the early members of a `publish-last` lockstep group release on their own. A `publish-last` member reuses a sibling tag at its version when one exists, and its exact pins are checked against the declared requirement at plan time.
diff --git a/packages/reflex-release/src/reflex_release/commands.py b/packages/reflex-release/src/reflex_release/commands.py
index dc434dc5aed..1991c624408 100644
--- a/packages/reflex-release/src/reflex_release/commands.py
+++ b/packages/reflex-release/src/reflex_release/commands.py
@@ -36,6 +36,7 @@
from .config import POST_RELEASE_INPUTS, POST_RELEASE_WORKFLOW_KEY, Config, is_final
from .devpins import (
LOCK_FILE,
+ PinUpgrade,
blocker_advice,
blocking_pins,
describe_blockers,
@@ -54,7 +55,7 @@
run_towncrier,
title_format,
)
-from .dist import pin_exact, verify_dist
+from .dist import check_exact_pin, pin_exact, verify_dist
from .gitutil import (
changed_files,
commit_exists,
@@ -172,8 +173,7 @@ def _lockstep_errors(config: Config, due: dict[str, str]) -> list[str]:
"""Verify the lockstep invariant for a release batch.
Every lockstep partner of a due package must either be due at the identical
- version in the same batch or already carry the tag for that version (the
- retry case where one half published earlier).
+ version in the same batch or already carry the tag for that version.
Args:
config: The repository configuration.
@@ -188,12 +188,8 @@ def _lockstep_errors(config: Config, due: dict[str, str]) -> list[str]:
partner_tag = config.tag_for(partner, version)
if due.get(partner) != version and not tag_exists(config.root, partner_tag):
errors.append(
- f"{package} v{version} is due but its lockstep partner {partner} "
- f"is neither due at v{version} nor already tagged {partner_tag}; "
- "publishing would break their exact pin. Re-run the Dispatch "
- "release workflow: selecting either member materializes the "
- "whole group, writing an empty changelog entry for members "
- "that have no news fragments."
+ f"{package} v{version} needs {partner} at v{version}, which is "
+ f"neither in this batch nor tagged {partner_tag}"
)
return errors
@@ -260,10 +256,10 @@ def cmd_detect(config: Config, ref_name: str) -> None:
fail("lockstep invariant violated; no package was published")
-def _drop_unpublishable_pins(
- config: Config, packages: list[str], action: str, explicit: bool
-) -> tuple[list[str], list[str]]:
- """Hold back packages whose dependency pins no published version satisfies.
+def _held_back(
+ blocked: dict[str, list[PinUpgrade]], planned: dict[str, str], explicit: bool
+) -> list[str]:
+ """Report the packages a plan held back over unsatisfiable dependency pins.
Materialization lifts a ``*.dev`` (and, for a final version, a prerelease)
dependency floor to the earliest published version that satisfies it. A
@@ -271,49 +267,99 @@ def _drop_unpublishable_pins(
releasable yet — releasing it would either publish an uninstallable pin or
stop at the publish-time gate with the changelog already bumped.
- A lockstep group is held back whole: its members only ever release together.
-
Args:
- config: The repository configuration.
- packages: The selected packages, lockstep groups already expanded.
- action: The release action being planned.
+ blocked: The unsatisfiable pins, by package.
+ planned: What is left of the plan.
explicit: Whether the selection was made by hand. An explicit selection
that cannot be released is an error; an auto-selected package is
simply left out of the batch.
Returns:
- The releasable packages and the human-readable reasons the others were
- held back.
+ The human-readable reasons, for the run summary.
"""
- blocked = blocking_pins(
- config, packages, allow_prereleases=action not in FINAL_ACTIONS
- )
- if not blocked:
- return packages, []
-
reasons = describe_blockers(blocked)
+ listing = "\n".join(f" {line}" for line in reasons)
if explicit:
- listing = "\n".join(f" {line}" for line in reasons)
fail(
"the selected package(s) declare dependency pins that no published "
f"version satisfies:\n{listing}\n\n{blocker_advice(blocked)}"
)
-
- held = {
- member
- for package in blocked
- for member in (package, *config.lockstep_partners(package))
- }
for line in reasons:
notice(f"held back from this release — {line}")
- remaining = [package for package in packages if package not in held]
- if not remaining:
+ if not planned:
fail(
- "every auto-selected package declares a dependency pin that no "
- "published version satisfies:\n"
- + "\n".join(f" {line}" for line in reasons)
+ "every auto-selected package is held back by a dependency pin that "
+ f"no published version satisfies:\n{listing}"
+ )
+ return reasons
+
+
+def _plan_versions(
+ config: Config,
+ packages: list[str],
+ action: str,
+ blocked: dict[str, list[PinUpgrade]],
+) -> tuple[dict[str, str], list[str]]:
+ """Plan the next version of each selected package and of the partners it needs.
+
+ Members of a lockstep group without ``publish-last`` advance together from
+ the highest baseline among them. A ``publish-last`` member advances from its
+ own baseline and needs every early member tagged at the new version; one not
+ tagged there yet is planned at it too.
+
+ A blocked package is held back before its version is planned, so an action
+ that does not apply to it cannot stop its siblings. A package whose needed
+ partner is blocked is held back with the partner.
+
+ Args:
+ config: The repository configuration.
+ packages: The selected packages.
+ action: One of the keys in :data:`~reflex_release.versions.ACTIONS`.
+ blocked: The unsatisfiable pins of the selected packages and of their
+ lockstep partners, by package.
+
+ Returns:
+ Package name to planned version, the selected packages first, and the
+ selected packages held back.
+ """
+ planned: dict[str, str] = {}
+ held: list[str] = []
+ for package in packages:
+ if package in blocked:
+ held.append(package)
+ continue
+ group = config.lockstep_group(package)
+ members = (
+ group.members
+ if group is not None and not group.publish_last
+ else (package,)
)
- return remaining, reasons
+ known = [v for m in members if (v := current_version(config, m)) is not None]
+ planned[package] = next_version(max(known, default=None), action, package)
+ for package in list(planned):
+ version = planned[package]
+ missing: list[str] = []
+ for partner in config.lockstep_partners(package):
+ if partner in planned:
+ continue
+ tag = config.tag_for(partner, version)
+ if tag_exists(config.root, tag):
+ notice(f"{package} v{version} reuses the published {tag}")
+ else:
+ missing.append(partner)
+ if any(partner in blocked for partner in missing):
+ held.append(package)
+ del planned[package]
+ continue
+ for partner in missing:
+ own = current_version(config, partner)
+ if own is not None and own >= Version(version):
+ fail(
+ f"{package} v{version} needs {config.tag_for(partner, version)}, "
+ f"but {partner} is already at v{own}"
+ )
+ planned[partner] = version
+ return planned, held
def cmd_plan(config: Config, action: str, selection: str) -> None:
@@ -323,8 +369,9 @@ def cmd_plan(config: Config, action: str, selection: str) -> None:
``$GITHUB_OUTPUT``. An empty selection auto-detects the packages to release:
those with pending news fragments — or, for ``release-from-prerelease``,
those whose changelog is topped by an alpha (their fragments are already
- consumed). A package whose dependency pins no published version satisfies is
- not eligible either way (see :func:`_drop_unpublishable_pins`).
+ consumed). Lockstep partners the selection needs are planned with it (see
+ :func:`_plan_versions`). A package whose dependency pins no published version
+ satisfies is not eligible either way (see :func:`_held_back`).
Args:
config: The repository configuration.
@@ -360,35 +407,37 @@ def cmd_plan(config: Config, action: str, selection: str) -> None:
fail(f"no packages selected and no package has {source}")
notice(f"no packages selected; auto-detected {', '.join(packages)}")
- # Lockstep members always release together at the same version, so selecting
- # one selects the whole group and the group shares a single baseline.
- for package in list(packages):
- packages.extend(
- partner
- for partner in config.lockstep_partners(package)
- if partner not in packages
+ candidates = list(
+ dict.fromkeys(
+ name
+ for package in packages
+ for name in (package, *config.lockstep_partners(package))
)
-
- packages, disqualified = _drop_unpublishable_pins(
- config, packages, action, explicit=how == "explicit"
)
+ blocked = blocking_pins(
+ config, candidates, allow_prereleases=action not in FINAL_ACTIONS
+ )
+ planned, held = _plan_versions(config, packages, action, blocked)
+ disqualified = _held_back(blocked, planned, how == "explicit") if held else []
+ if errors := _lockstep_errors(config, planned):
+ fail("\n".join(errors))
releases: list[dict[str, str]] = []
- for package in packages:
- group = config.lockstep_group(package)
- members = group.members if group is not None else (package,)
- baselines = [current_version(config, member) for member in members]
- known = [version for version in baselines if version is not None]
- current = max(known) if known else None
- planned = next_version(current, action, package)
- tag = config.tag_for(package, planned)
+ for package, version in planned.items():
+ tag = config.tag_for(package, version)
if tag_exists(config.root, tag):
fail(f"tag {tag} already exists")
+ # Checked here as well as at build time, before any changelog is bumped.
+ pyproject = config.package_path(package) / "pyproject.toml"
+ for target in config.exact_pin_targets(package):
+ check_exact_pin(
+ pyproject, config.distribution_name(target), Version(version)
+ )
own = current_version(config, package)
releases.append({
"package": package,
"current": str(own) if own is not None else "",
- "next": planned,
+ "next": version,
"tag": tag,
})
@@ -560,8 +609,14 @@ def cmd_prepare_publish(
notice(f"{package} has no CHANGELOG.md; skipping changelog check.")
for partner in config.lockstep_partners(package):
- if tag_exists(config.root, config.tag_for(partner, str(version))):
+ partner_tag = config.tag_for(partner, str(version))
+ if tag_exists(config.root, partner_tag):
continue
+ if config.publishes_last(package):
+ fail(
+ f"{package} v{version} publishes after {partner}, but "
+ f"{partner_tag} is not tagged yet"
+ )
partner_path = config.changelog_path(partner)
partner_newest = (
latest_version(partner_path.read_text(encoding="utf-8"))
@@ -618,9 +673,8 @@ def cmd_prepare_publish(
def cmd_pin_lockstep(config: Config, package: str, version: str) -> None:
"""Pin a package's lockstep siblings to the exact release version.
- Lockstep packages release together at one version, so the sibling that
- publishes last must ship metadata depending on exactly the versions
- published alongside it rather than on a floor.
+ A ``publish-last`` member depends on its siblings at the identical version,
+ published in this batch or an earlier one.
Args:
config: The repository configuration.
diff --git a/packages/reflex-release/src/reflex_release/config.py b/packages/reflex-release/src/reflex_release/config.py
index 5e7bdbc9909..b1bf7205800 100644
--- a/packages/reflex-release/src/reflex_release/config.py
+++ b/packages/reflex-release/src/reflex_release/config.py
@@ -119,15 +119,16 @@ def job_id(self) -> str:
@dataclasses.dataclass(frozen=True)
class LockstepGroup:
- """A set of packages that must always release together at the same version.
+ """Packages that release at one version.
Attributes:
members: The package names in the group (at least two).
- publish_last: Members that publish only after every other member of the
- group has been uploaded and tagged — used when they depend on their
- siblings at an exact version.
- pin_exact: Whether each ``publish_last`` member's requirement on its
- siblings is rewritten to ``== `` before building.
+ publish_last: Members that publish only after the other members are
+ uploaded and tagged at the same version — used when they depend on
+ those siblings at an exact version. Without it, every member
+ releases together; with it, the other members release on their own.
+ pin_exact: Whether each ``publish_last`` member's requirement on the
+ other members is rewritten to ``== `` before building.
"""
members: tuple[str, ...]
@@ -458,26 +459,30 @@ def lockstep_group(self, package: str) -> LockstepGroup | None:
package: The package name.
Returns:
- The group, or None when the package releases independently.
+ The group, or None when the package does not belong to one.
"""
return next(
(group for group in self.lockstep if package in group.members), None
)
def lockstep_partners(self, package: str) -> tuple[str, ...]:
- """Return the packages that must release alongside a package.
+ """Return the siblings a package needs released at its own version.
Args:
package: The package name.
Returns:
- The other members of the package's lockstep group, or an empty
- tuple.
+ Every other member of a group without ``publish-last``; the early
+ members for a ``publish-last`` member; otherwise an empty tuple.
"""
group = self.lockstep_group(package)
if group is None:
return ()
- return tuple(member for member in group.members if member != package)
+ if not group.publish_last:
+ return tuple(member for member in group.members if member != package)
+ if package not in group.publish_last:
+ return ()
+ return tuple(m for m in group.members if m not in group.publish_last)
def publishes_last(self, package: str) -> bool:
"""Return whether a package must publish after its lockstep siblings.
@@ -502,9 +507,9 @@ def exact_pin_targets(self, package: str) -> tuple[str, ...]:
package's ``pyproject.toml``, or an empty tuple.
"""
group = self.lockstep_group(package)
- if group is None or not group.pin_exact or package not in group.publish_last:
+ if group is None or not group.pin_exact:
return ()
- return tuple(member for member in group.members if member != package)
+ return self.lockstep_partners(package)
def custom_build_for(self, package: str) -> CustomBuild | None:
"""Return the repository-supplied workflow that builds a package.
diff --git a/packages/reflex-release/src/reflex_release/dist.py b/packages/reflex-release/src/reflex_release/dist.py
index 7a7f691aabb..6f63f5dfb71 100644
--- a/packages/reflex-release/src/reflex_release/dist.py
+++ b/packages/reflex-release/src/reflex_release/dist.py
@@ -10,6 +10,7 @@
from collections.abc import Sequence
from pathlib import Path
+from packaging.requirements import Requirement
from packaging.version import InvalidVersion, Version
from .actions import ReleaseError, fail
@@ -141,17 +142,18 @@ def verify_dist(
return len(files)
-def pin_exact(pyproject: Path, dependency: str, version: Version) -> None:
- """Rewrite a lower-bound requirement on a dependency to an exact pin.
-
- Lockstep packages release together at one version, so a package that
- publishes last must depend on exactly the sibling version published
- alongside it rather than on a floor that a future release would satisfy.
+def check_exact_pin(
+ pyproject: Path, dependency: str, version: Version
+) -> re.Match[str]:
+ """Locate the requirement :func:`pin_exact` rewrites and check it admits the pin.
Args:
pyproject: The ``pyproject.toml`` of the package being built.
dependency: The distribution name to pin.
version: The version to pin it to.
+
+ Returns:
+ The match of the quoted requirement string in the file's text.
"""
text = pyproject.read_text(encoding="utf-8")
# Requirement strings are quoted TOML values, so the rewrite is anchored on
@@ -169,8 +171,27 @@ def pin_exact(pyproject: Path, dependency: str, version: Version) -> None:
f'expected exactly one "{dependency} " requirement in '
f"{pyproject}, found {len(matches)}"
)
- new_pin = f'"{dependency}{matches[0]["extras"] or ""} == {version}"'
+ requirement = Requirement(matches[0].group(0)[1:-1])
+ if not requirement.specifier.contains(version, prereleases=True):
+ fail(f"{dependency} v{version} does not satisfy {requirement} in {pyproject}")
+ return matches[0]
+
+
+def pin_exact(pyproject: Path, dependency: str, version: Version) -> None:
+ """Rewrite a lower-bound requirement on a dependency to an exact pin.
+
+ A ``publish-last`` member depends on its siblings at the identical version,
+ published in this batch or an earlier one, so their floors become
+ ``== `` in the metadata it ships.
+
+ Args:
+ pyproject: The ``pyproject.toml`` of the package being built.
+ dependency: The distribution name to pin.
+ version: The version to pin it to.
+ """
+ match = check_exact_pin(pyproject, dependency, version)
+ new_pin = f'"{dependency}{match["extras"] or ""} == {version}"'
pyproject.write_text(
- text.replace(matches[0].group(0), new_pin, 1), encoding="utf-8"
+ match.string.replace(match.group(0), new_pin, 1), encoding="utf-8"
)
sys.stderr.write(f"Pinned {new_pin} in {pyproject}\n")
diff --git a/packages/reflex-release/src/reflex_release/scaffold.py b/packages/reflex-release/src/reflex_release/scaffold.py
index 52b44092b44..708e77885d0 100644
--- a/packages/reflex-release/src/reflex_release/scaffold.py
+++ b/packages/reflex-release/src/reflex_release/scaffold.py
@@ -173,7 +173,8 @@ class DispatchInput:
input_id: The ``workflow_dispatch`` input name.
description: The label GitHub shows next to the checkbox.
packages: The packages the checkbox selects — more than one for a
- lockstep group, whose members can only be released together.
+ lockstep group without ``publish-last``, whose members only ever
+ release together.
"""
input_id: str
@@ -196,9 +197,10 @@ def _input_id(package: str) -> str:
def dispatch_inputs(config: Config) -> list[DispatchInput]:
"""List the package checkboxes the Dispatch release workflow offers.
- Lockstep members share one checkbox: they can only be released together, so
+ Lockstep members that only ever release together share one checkbox;
offering them separately would invite a selection the planner has to
- silently widen anyway.
+ silently widen anyway. Members of a ``publish-last`` group release
+ separately, so each gets its own.
Args:
config: The repository configuration.
@@ -211,7 +213,12 @@ def dispatch_inputs(config: Config) -> list[DispatchInput]:
for package in releasable_packages(config):
if package in covered:
continue
- partners = config.lockstep_partners(package)
+ group = config.lockstep_group(package)
+ partners = (
+ ()
+ if group is not None and group.publish_last
+ else config.lockstep_partners(package)
+ )
covered.add(package)
covered.update(partners)
inputs.append(
diff --git a/packages/reflex-release/src/reflex_release/templates/workflows/dispatch_release.yml b/packages/reflex-release/src/reflex_release/templates/workflows/dispatch_release.yml
index 3997c618be3..06f48186841 100644
--- a/packages/reflex-release/src/reflex_release/templates/workflows/dispatch_release.yml
+++ b/packages/reflex-release/src/reflex_release/templates/workflows/dispatch_release.yml
@@ -10,7 +10,8 @@ name: Dispatch release
# Selecting no package auto-selects the ones to release: those with pending
# news fragments — or, for release-from-prerelease, those whose changelog is
# topped by an alpha (the train's fragments are already consumed). Lockstep
-# groups share one checkbox: their members only ever release together.
+# groups without publish-last share one checkbox: their members only ever
+# release together. With publish-last, each member has its own.
#
# Materializing also lifts each released package's unshippable dependency
# floors — a *.dev pin, and a prerelease pin when the version is final — to the
diff --git a/packages/reflex-release/src/reflex_release/templates/workflows/release_from_changelog.yml b/packages/reflex-release/src/reflex_release/templates/workflows/release_from_changelog.yml
index a06369e079a..4dc8b6d8eae 100644
--- a/packages/reflex-release/src/reflex_release/templates/workflows/release_from_changelog.yml
+++ b/packages/reflex-release/src/reflex_release/templates/workflows/release_from_changelog.yml
@@ -17,9 +17,9 @@ name: Release from changelog
# @@PRERELEASE_PREFIX@@* or @@HOTFIX_PREFIX@@** (the Dispatch release workflow
# materializes alphas on @@PRERELEASE_PREFIX@@* branches).
#
-# Lockstep packages that pin their siblings exactly publish strictly after
-# every other package in the batch; detect fails closed if a lockstep
-# invariant is broken.
+# Lockstep packages that pin their siblings exactly publish in a second leg,
+# after the rest of the batch, and only once the siblings they pin are tagged;
+# detect fails closed if a lockstep invariant is broken.
#
# workflow_dispatch exists so the Dispatch release workflow can trigger a
# check on a branch it just pushed (pushes made with GITHUB_TOKEN do not fire
diff --git a/pyproject.toml b/pyproject.toml
index cb3fa082dca..e077dc02392 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -32,20 +32,21 @@ dependencies = [
"starlette >=1.3.1",
"typing_extensions >=4.13.0",
"wrapt >=1.17.0,<2.6",
- "reflex-base >= 0.9.13.dev0",
- "reflex-components-code >= 0.9.0",
- "reflex-components-core >= 0.9.6",
- "reflex-components-dataeditor >= 0.9.0",
- "reflex-components-gridjs >= 0.9.0",
- "reflex-components-lucide >= 0.9.0",
- "reflex-components-markdown >= 0.9.0",
- "reflex-components-moment >= 0.9.4",
- "reflex-components-plotly >= 0.9.0",
- "reflex-components-radix >= 0.9.9",
- "reflex-components-react-player >= 0.9.0",
- "reflex-components-recharts >= 0.9.0",
- "reflex-components-sonner >= 0.9.0",
- "reflex-hosting-cli >= 0.1.71",
+ "reflex-base >= 0.10.0a2.dev0",
+ "reflex-components-code >= 0.10.0a2.dev0",
+ "reflex-components-core >= 0.10.0a2.dev0",
+ "reflex-components-dataeditor >= 0.9.3.post2.dev0",
+ "reflex-components-gridjs >= 0.10.0a2.dev0",
+ "reflex-components-lucide >= 1.0.5.dev0",
+ "reflex-components-markdown >= 0.10.0a2.dev0",
+ "reflex-components-moment >= 0.10.0a2.dev0",
+ "reflex-components-plotly >= 0.10.0a2.dev0",
+ "reflex-components-radix >= 0.10.0a2.dev0",
+ "reflex-components-react-player >= 0.9.3.dev0",
+ "reflex-components-recharts >= 0.10.0a2.dev0",
+ "reflex-components-sonner >= 0.9.5.dev0",
+ # 0.1.73a1 predates the Python 3.11 train; the floor lifts to the next alpha.
+ "reflex-hosting-cli >= 0.1.72.post2.dev0, != 0.1.73a1",
]
classifiers = [
@@ -414,8 +415,8 @@ internal-packages = ["reflex-components-internal", "reflex-site-shared"]
# changelog detection, no news fragment, and publish refuses it.
never-publish-packages = ["integrations-docs", "reflex-bench"]
-# reflex's metadata pins reflex-base exactly, so the two always release together
-# at one version and reflex uploads only after reflex-base is on PyPI.
+# reflex pins reflex-base exactly and publishes after it, reusing a base tag at
+# its own version when one exists. reflex-base releases on its own.
[[tool.reflex-release.lockstep]]
members = ["reflex", "reflex-base"]
publish-last = ["reflex"]
diff --git a/tests/units/reflex_release/conftest.py b/tests/units/reflex_release/conftest.py
index 6a01f651e60..4aa81299537 100644
--- a/tests/units/reflex_release/conftest.py
+++ b/tests/units/reflex_release/conftest.py
@@ -52,7 +52,7 @@ def commit_all(repo: Path, message: str = "wip") -> None:
git(repo, "commit", "-q", "-m", message)
-def write_lockstep(repo: Path) -> None:
+def write_lockstep(repo: Path, *, publish_last: bool = True) -> None:
"""Make the repository's two packages a lockstep group.
The root package publishes last and pins the sub-package exactly, mirroring
@@ -60,6 +60,7 @@ def write_lockstep(repo: Path) -> None:
Args:
repo: The repository root.
+ publish_last: Whether the root publishes last and pins its sibling exactly.
"""
pyproject = repo / "pyproject.toml"
pyproject.write_text(
@@ -67,9 +68,8 @@ def write_lockstep(repo: Path) -> None:
"\n[tool.towncrier]",
"\n[[tool.reflex-release.lockstep]]\n"
'members = ["mypkg", "widget-core"]\n'
- 'publish-last = ["mypkg"]\n'
- "pin-exact = true\n"
- "\n[tool.towncrier]",
+ + ('publish-last = ["mypkg"]\npin-exact = true\n' if publish_last else "")
+ + "\n[tool.towncrier]",
),
encoding="utf-8",
)
diff --git a/tests/units/reflex_release/test_commands.py b/tests/units/reflex_release/test_commands.py
index 78933ad332e..7f53fea49b8 100644
--- a/tests/units/reflex_release/test_commands.py
+++ b/tests/units/reflex_release/test_commands.py
@@ -178,6 +178,22 @@ def test_detect_accepts_an_already_tagged_lockstep_partner(
]
+def test_detect_allows_a_lockstep_dependency_to_publish_alone(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """An early member is detectable without a matching dependent release."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ git(repo, "tag", "v1.1.0a1")
+ set_changelog(reloaded, "widget-core", "## 1.1.0a2\n\nNew.\n")
+
+ commands.cmd_detect(reloaded, "r/pre-train")
+
+ assert [r["package"] for r in json.loads(outputs()["packages"])] == ["widget-core"]
+ assert outputs()["any_last"] == "false"
+
+
def test_plan_auto_selects_packages_with_fragments(
config: Config, outputs: Outputs
) -> None:
@@ -203,7 +219,7 @@ def test_plan_uses_explicit_selection(config: Config, outputs: Outputs) -> None:
def test_plan_expands_lockstep_groups_to_one_version(
config: Config, repo: Path, outputs: Outputs
) -> None:
- write_lockstep(repo)
+ write_lockstep(repo, publish_last=False)
reloaded = load_config(repo)
set_changelog(
reloaded, "mypkg", "## v1.4.0 (2026-01-01)\n\nNo significant changes.\n"
@@ -220,6 +236,108 @@ def test_plan_expands_lockstep_groups_to_one_version(
}
+def test_plan_selecting_a_dependency_does_not_select_publish_last(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """An early member advances from its own baseline without the dependent."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ set_changelog(reloaded, "widget-core", "## 1.1.0a1\n\nOld.\n")
+
+ commands.cmd_plan(reloaded, "continued-prerelease", "widget-core")
+
+ assert {r["package"]: r["next"] for r in json.loads(outputs()["releases"])} == {
+ "widget-core": "1.1.0a2"
+ }
+
+
+def test_plan_publish_last_reuses_the_partner_tag_at_its_version(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """A dependent takes the matching tag even though the sibling has moved on."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ set_changelog(reloaded, "widget-core", "## 1.1.0a3\n\nNewer.\n")
+ git(repo, "tag", "widget-core-v1.1.0a2")
+ git(repo, "tag", "widget-core-v1.1.0a3")
+ # The sibling's current pins do not matter: its tagged metadata is what ships.
+ pyproject = reloaded.package_path("widget-core") / "pyproject.toml"
+ pyproject.write_text(
+ pyproject.read_text() + 'dependencies = ["third-party >= 9.9.9.dev1"]\n'
+ )
+
+ commands.cmd_plan(reloaded, "continued-prerelease", "mypkg")
+
+ assert {r["package"]: r["next"] for r in json.loads(outputs()["releases"])} == {
+ "mypkg": "1.1.0a2"
+ }
+
+
+def test_plan_selected_early_member_advances_beside_a_reusing_dependent(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """Selecting both plans each from its own baseline."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ set_changelog(reloaded, "widget-core", "## 1.1.0a2\n\nNewer.\n")
+ git(repo, "tag", "widget-core-v1.1.0a2")
+
+ commands.cmd_plan(reloaded, "continued-prerelease", "mypkg,widget-core")
+
+ assert {r["package"]: r["next"] for r in json.loads(outputs()["releases"])} == {
+ "mypkg": "1.1.0a2",
+ "widget-core": "1.1.0a3",
+ }
+
+
+def test_plan_publish_last_includes_an_unreleased_partner(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """Selecting the dependent plans missing siblings at the same target."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ for package in ("mypkg", "widget-core"):
+ set_changelog(reloaded, package, "## 1.1.0a1\n\nOld.\n")
+
+ commands.cmd_plan(reloaded, "continued-prerelease", "mypkg")
+
+ assert {r["package"]: r["next"] for r in json.loads(outputs()["releases"])} == {
+ "mypkg": "1.1.0a2",
+ "widget-core": "1.1.0a2",
+ }
+
+
+def test_plan_requires_a_matching_tag_when_a_partner_has_advanced(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """An advanced sibling cannot substitute a different release version."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ set_changelog(reloaded, "widget-core", "## 1.1.0a3\n\nNewer.\n")
+ git(repo, "tag", "widget-core-v1.1.0a3")
+
+ with pytest.raises(ReleaseError, match=r"already at v1\.1\.0a3"):
+ commands.cmd_plan(reloaded, "continued-prerelease", "mypkg")
+
+
+def test_plan_rejects_reusing_a_tag_the_declared_requirement_excludes(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """A floor raised past the reusable sibling version stops the plan."""
+ write_lockstep(repo)
+ reloaded = dev_pin(repo, "widget-core >= 1.1.0a3.dev0")
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ set_changelog(reloaded, "widget-core", "## 1.1.0a2\n\nNew.\n")
+ git(repo, "tag", "widget-core-v1.1.0a2")
+
+ with pytest.raises(ReleaseError, match="does not satisfy"):
+ commands.cmd_plan(reloaded, "continued-prerelease", "mypkg")
+
+
def test_plan_rejects_an_existing_tag(
config: Config, repo: Path, outputs: Outputs
) -> None:
@@ -379,7 +497,7 @@ def test_materialize_writes_an_empty_entry_for_a_lockstep_partner(
config: Config, repo: Path, outputs: Outputs
) -> None:
"""A member dragged along by its lockstep sibling needs no hand-written entry."""
- write_lockstep(repo)
+ write_lockstep(repo, publish_last=False)
reloaded = load_config(repo)
fragment(reloaded, "widget-core", "3.feature.md", "A real change.")
# The partner has nothing to say — not even a news directory.
@@ -569,7 +687,7 @@ def test_prepare_publish_will_not_auto_bump_a_non_internal_package(
def test_prepare_publish_requires_a_materialized_lockstep_partner(
config: Config, repo: Path, outputs: Outputs
) -> None:
- write_lockstep(repo)
+ write_lockstep(repo, publish_last=False)
reloaded = load_config(repo)
set_changelog(
reloaded, "mypkg", "## v1.2.0 (2026-01-01)\n\nNo significant changes.\n"
@@ -578,6 +696,60 @@ def test_prepare_publish_requires_a_materialized_lockstep_partner(
commands.cmd_prepare_publish(reloaded, "mypkg", "1.2.0", "main")
+def test_prepare_publish_allows_an_early_member_without_its_dependent(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ set_changelog(reloaded, "widget-core", "## 1.2.0\n\nNew.\n")
+
+ commands.cmd_prepare_publish(reloaded, "widget-core", "1.2.0", "main")
+
+ assert outputs()["skipped"] == "false"
+
+
+def test_prepare_publish_last_requires_a_published_partner(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """A matching changelog alone cannot authorize a dependent's publication."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ for package in ("mypkg", "widget-core"):
+ set_changelog(reloaded, package, "## 1.2.0\n\nNew.\n")
+
+ with pytest.raises(ReleaseError, match="not tagged yet"):
+ commands.cmd_prepare_publish(reloaded, "mypkg", "1.2.0", "main")
+
+ git(repo, "tag", "widget-core-v1.2.0")
+ commands.cmd_prepare_publish(reloaded, "mypkg", "1.2.0", "main")
+ assert outputs()["skipped"] == "false"
+
+
+def test_prepare_publish_last_members_do_not_wait_for_each_other(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """Two publish-last members need the early member's tag, not one another's."""
+ peer = repo / "packages" / "widget-peer"
+ peer.mkdir()
+ (peer / "pyproject.toml").write_text('[project]\nname = "widget-peer"\n')
+ write_lockstep(repo)
+ pyproject = repo / "pyproject.toml"
+ pyproject.write_text(
+ pyproject.read_text().replace(
+ 'members = ["mypkg", "widget-core"]\npublish-last = ["mypkg"]',
+ 'members = ["mypkg", "widget-core", "widget-peer"]\n'
+ 'publish-last = ["mypkg", "widget-peer"]',
+ )
+ )
+ reloaded = load_config(repo)
+ set_changelog(reloaded, "mypkg", "## 1.2.0\n\nNew.\n")
+ git(repo, "tag", "widget-core-v1.2.0")
+
+ commands.cmd_prepare_publish(reloaded, "mypkg", "1.2.0", "main")
+
+ assert outputs()["skipped"] == "false"
+
+
def test_prepare_publish_rejects_unknown_packages(
config: Config, outputs: Outputs
) -> None:
@@ -1569,7 +1741,7 @@ def test_plan_holds_back_a_whole_lockstep_group(
config: Config, repo: Path, outputs: Outputs
) -> None:
"""Members only ever release together, so one blocker holds back the group."""
- write_lockstep(repo)
+ write_lockstep(repo, publish_last=False)
# Not the lockstep sibling, which pin-lockstep rewrites at build time.
reloaded = dev_pin(repo, "third-party >= 9.9.9.dev1")
fragment(reloaded, "widget-core", "2.feature.md")
@@ -1577,6 +1749,148 @@ def test_plan_holds_back_a_whole_lockstep_group(
commands.cmd_plan(reloaded, "release-minor", "")
+def test_plan_holds_back_publish_last_without_holding_back_its_dependency(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """A dependent's blockers leave its early sibling eligible for release."""
+ write_lockstep(repo)
+ reloaded = dev_pin(repo, "third-party >= 9.9.9.dev1")
+ fragment(reloaded, "mypkg", "1.feature.md")
+ fragment(reloaded, "widget-core", "2.feature.md")
+
+ commands.cmd_plan(reloaded, "release-minor", "")
+
+ assert [r["package"] for r in json.loads(outputs()["releases"])] == ["widget-core"]
+
+
+@pytest.mark.parametrize("selection", ["mypkg", "mypkg,widget-core"])
+def test_plan_rejects_an_explicitly_selected_blocked_dependent(
+ config: Config, repo: Path, outputs: Outputs, selection: str
+) -> None:
+ """Asking for a package that cannot release is an error, not a silent drop."""
+ write_lockstep(repo)
+ reloaded = dev_pin(repo, "third-party >= 9.9.9.dev1")
+ fragment(reloaded, "widget-core", "2.feature.md")
+
+ with pytest.raises(ReleaseError, match="no published version satisfies"):
+ commands.cmd_plan(reloaded, "release-minor", selection)
+
+
+def test_plan_holds_back_publish_last_when_its_dependency_is_blocked(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """A blocked early sibling holds back dependents requiring its release."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ pyproject = reloaded.package_path("widget-core") / "pyproject.toml"
+ pyproject.write_text(
+ pyproject.read_text() + 'dependencies = ["third-party >= 9.9.9.dev1"]\n'
+ )
+ fragment(reloaded, "mypkg", "1.feature.md")
+ fragment(reloaded, "widget-core", "2.feature.md")
+
+ with pytest.raises(ReleaseError, match="every auto-selected package"):
+ commands.cmd_plan(reloaded, "release-minor", "")
+
+
+def test_plan_does_not_republish_a_matching_partner_of_a_blocked_dependent(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """A held dependent does not bump a sibling already at its matching target."""
+ write_lockstep(repo)
+ reloaded = dev_pin(repo, "third-party >= 9.9.9.dev1")
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ set_changelog(reloaded, "widget-core", "## 1.1.0a2\n\nNew.\n")
+ git(repo, "tag", "widget-core-v1.1.0a2")
+ fragment(reloaded, "mypkg", "1.feature.md")
+
+ with pytest.raises(ReleaseError, match="every auto-selected package"):
+ commands.cmd_plan(reloaded, "continued-prerelease", "")
+
+
+def test_plan_blocked_dependent_does_not_cancel_a_requested_sibling_release(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """An early sibling with news of its own still advances from its baseline."""
+ write_lockstep(repo)
+ reloaded = dev_pin(repo, "third-party >= 9.9.9.dev1")
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ set_changelog(reloaded, "widget-core", "## 1.1.0a2\n\nNew.\n")
+ git(repo, "tag", "widget-core-v1.1.0a2")
+ fragment(reloaded, "mypkg", "1.feature.md")
+ fragment(reloaded, "widget-core", "2.feature.md")
+
+ commands.cmd_plan(reloaded, "continued-prerelease", "")
+
+ assert {r["package"]: r["next"] for r in json.loads(outputs()["releases"])} == {
+ "widget-core": "1.1.0a3"
+ }
+
+
+def test_plan_holds_back_a_blocked_dependent_before_applying_the_action(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """An action that does not apply to a held dependent cannot stop its sibling."""
+ write_lockstep(repo)
+ reloaded = dev_pin(repo, "third-party >= 9.9.9.dev1")
+ set_changelog(reloaded, "mypkg", "## 1.1.0a1\n\nOld.\n")
+ set_changelog(reloaded, "widget-core", "## 1.0.0\n\nOld.\n")
+ fragment(reloaded, "mypkg", "1.feature.md")
+ fragment(reloaded, "widget-core", "2.feature.md")
+
+ commands.cmd_plan(reloaded, "new-prerelease-minor", "")
+
+ assert {r["package"]: r["next"] for r in json.loads(outputs()["releases"])} == {
+ "widget-core": "1.1.0a1"
+ }
+
+
+def test_dependency_first_phases_materialize_and_publish_matching_versions(
+ config: Config, repo: Path, outputs: Outputs
+) -> None:
+ """Three phases lift dev pins and reuse the base's exact published version."""
+ write_lockstep(repo)
+ renderer = repo / "packages" / "widget-renderer"
+ renderer.mkdir()
+ (renderer / "news").mkdir()
+ (renderer / "pyproject.toml").write_text(
+ '[project]\nname = "widget-renderer"\n'
+ 'dependencies = ["widget-core >= 1.1.0a2.dev1"]\n'
+ )
+ pyproject = repo / "pyproject.toml"
+ pyproject.write_text(
+ pyproject.read_text().replace(
+ '"widget-core >= 0.1.0"',
+ '"widget-core >= 1.1.0a2.dev1", "widget-renderer >= 1.1.0a2.dev1"',
+ )
+ )
+ reloaded = load_config(repo)
+ for package in ("mypkg", "widget-core", "widget-renderer"):
+ set_changelog(reloaded, package, "## 1.1.0a1\n\nOld.\n")
+ git(repo, "tag", reloaded.tag_for(package, "1.1.0a1"))
+ fragment(reloaded, package, "1.feature.md", "New.")
+ commit_all(repo)
+
+ for package in ("widget-core", "widget-renderer", "mypkg"):
+ commands.cmd_plan(reloaded, "continued-prerelease", "")
+ releases = json.loads(outputs()["releases"])
+ assert [(r["package"], r["next"]) for r in releases] == [(package, "1.1.0a2")]
+ commands.cmd_materialize(
+ reloaded, "continued-prerelease", outputs()["releases"]
+ )
+ commands.cmd_detect(reloaded, "r/pre-train")
+ leg = "last_packages" if package == "mypkg" else "packages"
+ assert [r["package"] for r in json.loads(outputs()[leg])] == [package]
+ commands.cmd_prepare_publish(reloaded, package, "1.1.0a2", "r/pre-train")
+ assert outputs()["skipped"] == "false"
+ commit_all(repo)
+ git(repo, "tag", reloaded.tag_for(package, "1.1.0a2"))
+
+ commands.cmd_pin_lockstep(reloaded, "mypkg", "1.1.0a2")
+ assert '"widget-core == 1.1.0a2"' in pyproject.read_text()
+ assert '"widget-renderer >= 1.1.0a2"' in pyproject.read_text()
+
+
def test_plan_accepts_a_pin_a_prerelease_can_satisfy(
config: Config, repo: Path, outputs: Outputs
) -> None:
diff --git a/tests/units/reflex_release/test_config.py b/tests/units/reflex_release/test_config.py
index 1d948acc3a7..d23b54216b9 100644
--- a/tests/units/reflex_release/test_config.py
+++ b/tests/units/reflex_release/test_config.py
@@ -159,13 +159,39 @@ def test_lockstep_helpers(config: Config, repo: Path) -> None:
)
reloaded = load_config(repo)
assert reloaded.lockstep_partners("mypkg") == ("widget-core",)
- assert reloaded.lockstep_partners("widget-core") == ("mypkg",)
+ assert reloaded.lockstep_partners("widget-core") == ()
assert reloaded.publishes_last("mypkg")
assert not reloaded.publishes_last("widget-core")
assert reloaded.exact_pin_targets("mypkg") == ("widget-core",)
assert reloaded.exact_pin_targets("widget-core") == ()
+def test_lockstep_without_publish_last_remains_symmetric(repo: Path) -> None:
+ """Groups without publication ordering still require all their partners."""
+ write_lockstep(repo, publish_last=False)
+ config = load_config(repo)
+ assert config.lockstep_partners("mypkg") == ("widget-core",)
+ assert config.lockstep_partners("widget-core") == ("mypkg",)
+
+
+def test_publish_last_members_need_only_the_early_members(repo: Path) -> None:
+ (repo / "packages" / "widget-peer").mkdir()
+ (repo / "packages" / "widget-peer" / "pyproject.toml").write_text(
+ '[project]\nname = "widget-peer"\n'
+ )
+ write_config(
+ repo,
+ 'root-package = "mypkg"\npackages-dir = "packages"\n\n'
+ "[[tool.reflex-release.lockstep]]\n"
+ 'members = ["mypkg", "widget-core", "widget-peer"]\n'
+ 'publish-last = ["mypkg", "widget-peer"]\npin-exact = true\n',
+ )
+ config = load_config(repo)
+ assert config.lockstep_partners("mypkg") == ("widget-core",)
+ assert config.lockstep_partners("widget-peer") == ("widget-core",)
+ assert config.exact_pin_targets("widget-peer") == ("widget-core",)
+
+
def test_empty_latest_release_package_disables_the_badge(
config: Config, repo: Path
) -> None:
diff --git a/tests/units/reflex_release/test_dist.py b/tests/units/reflex_release/test_dist.py
index 57f09ac25b0..d9ceb12fdfb 100644
--- a/tests/units/reflex_release/test_dist.py
+++ b/tests/units/reflex_release/test_dist.py
@@ -138,6 +138,24 @@ def test_pin_exact_ignores_similar_names(tmp_path: Path) -> None:
assert '"widget-core == 1.2.3"' in pyproject.read_text(encoding="utf-8")
+@pytest.mark.parametrize(
+ "requirement",
+ ["widget-core >= 1.2.4.dev1", "widget-core < 1.2.3", "widget-core != 1.2.3"],
+)
+def test_pin_exact_preserves_constraints_when_reusing_a_published_version(
+ tmp_path: Path, requirement: str
+) -> None:
+ """An exact release pin cannot silently override the required sibling version."""
+ pyproject = tmp_path / "pyproject.toml"
+ original = f'[project]\ndependencies = ["{requirement}"]\n'
+ pyproject.write_text(original)
+
+ with pytest.raises(ReleaseError, match="does not satisfy"):
+ pin_exact(pyproject, "widget-core", Version("1.2.3"))
+
+ assert pyproject.read_text() == original
+
+
@pytest.mark.parametrize(
"dependencies",
['["requests >= 2"]', '["widget-core >= 1", "widget-core >= 2"]'],
diff --git a/tests/units/reflex_release/test_scaffold.py b/tests/units/reflex_release/test_scaffold.py
index 4f7b9db83fd..1b57896163f 100644
--- a/tests/units/reflex_release/test_scaffold.py
+++ b/tests/units/reflex_release/test_scaffold.py
@@ -342,7 +342,7 @@ def test_every_generated_run_step_pins_the_shell(config: Config, repo: Path) ->
def test_dispatch_inputs_give_a_lockstep_group_one_checkbox(
config: Config, repo: Path
) -> None:
- write_lockstep(repo)
+ write_lockstep(repo, publish_last=False)
reloaded = load_config(repo)
entries = dispatch_inputs(reloaded)
assert [entry.input_id for entry in entries] == ["mypkg"]
@@ -353,7 +353,7 @@ def test_dispatch_inputs_give_a_lockstep_group_one_checkbox(
def test_checkboxes_select_every_member_of_a_lockstep_group(
config: Config, repo: Path
) -> None:
- write_lockstep(repo)
+ write_lockstep(repo, publish_last=False)
reloaded = load_config(repo)
rendered = render("dispatch_release.yml", reloaded)
assert " mypkg:\n" in rendered
@@ -365,6 +365,22 @@ def test_checkboxes_select_every_member_of_a_lockstep_group(
assert packages == "${{ inputs.mypkg && 'mypkg,widget-core' || '' }}"
+def test_dispatch_inputs_select_publish_last_and_its_dependency_separately(
+ config: Config, repo: Path
+) -> None:
+ """The workflow form can select an early sibling without its dependent."""
+ write_lockstep(repo)
+ reloaded = load_config(repo)
+ entries = dispatch_inputs(reloaded)
+ assert [(entry.input_id, entry.packages) for entry in entries] == [
+ ("mypkg", ("mypkg",)),
+ ("widget_core", ("widget-core",)),
+ ]
+ rendered = render("dispatch_release.yml", reloaded)
+ assert "${{ inputs.mypkg && 'mypkg' || '' }}" in rendered
+ assert "${{ inputs.widget_core && 'widget-core' || '' }}" in rendered
+
+
def test_selection_parser_accepts_the_folded_scalar_shape() -> None:
"""The contract between the rendered PACKAGES scalar and the planner.
diff --git a/tests/units/test_check_min_deps.py b/tests/units/test_check_min_deps.py
index 8924efeafbb..e6d17412b7a 100644
--- a/tests/units/test_check_min_deps.py
+++ b/tests/units/test_check_min_deps.py
@@ -425,19 +425,32 @@ def test_build_wheelhouse_builds_every_source_once(
"""
fake_run = _FakeRun(
built={
- # Both satisfy what the root package declares, so neither is rebuilt.
+ # Both satisfy the fixture's floors, so neither is rebuilt.
"reflex-base": "0.9.13.dev1+abc1234",
"reflex-hosting-cli": "0.1.71.post1.dev0+abc1234",
}
)
monkeypatch.setattr(check_min_deps, "_run", fake_run)
sources = (
- check_min_deps.REPO_ROOT / "packages" / "reflex-base",
- check_min_deps.REPO_ROOT / "packages" / "reflex-hosting-cli",
+ tmp_path / "reflex-base",
+ tmp_path / "reflex-hosting-cli",
+ )
+ for source in sources:
+ source.mkdir()
+ (source / "pyproject.toml").write_text(f'[project]\nname = "{source.name}"\n')
+ consumer = tmp_path / "consumer"
+ _write_pyproject(
+ consumer, ["reflex-base >= 0.9.12.dev0", "reflex-hosting-cli >= 0.1.71"]
)
wheelhouse = tmp_path / "nested" / "wheelhouse"
- package = _fake_package(sources)
+ package = check_min_deps.Package(
+ name="demo",
+ project_dir=consumer,
+ source_dir=consumer,
+ extras=(),
+ local_sources=sources,
+ )
versions, detail = check_min_deps.build_wheelhouse(
[package], wheelhouse, build=True
)
From 2d0638313c4e07e1501e16abee5d395ea4e780e0 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 04:47:20 +0000
Subject: [PATCH 05/25] Materialize changelogs for reflex-base@0.10.0a2
(continued-prerelease)
---
packages/reflex-base/CHANGELOG.md | 16 ++++++++++++++++
.../news/+backend-class-assignment.bugfix.md | 1 -
.../news/+backend-var-fstring.bugfix.md | 1 -
.../news/+drop-python-310.breaking.md | 1 -
.../news/+private-dunder-fields.feature.md | 1 -
5 files changed, 16 insertions(+), 4 deletions(-)
delete mode 100644 packages/reflex-base/news/+backend-class-assignment.bugfix.md
delete mode 100644 packages/reflex-base/news/+backend-var-fstring.bugfix.md
delete mode 100644 packages/reflex-base/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-base/news/+private-dunder-fields.feature.md
diff --git a/packages/reflex-base/CHANGELOG.md b/packages/reflex-base/CHANGELOG.md
index fac1123608d..663b9f24504 100644
--- a/packages/reflex-base/CHANGELOG.md
+++ b/packages/reflex-base/CHANGELOG.md
@@ -1,3 +1,19 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+### Features
+
+- A double-underscore state attribute (a name-mangled `__private` name or a dunder) can now be a backend var by declaring it with an explicit `rx.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](https://github.com/reflex-dev/reflex/issues/7465))
+
+### Bug Fixes
+
+- Formatting a backend var as a string, e.g. `width=f"{State._size}px"`, now raises `BackendVarFormatError` (a `VarTypeError`) instead of silently embedding the field's repr in the page. ([#7456](https://github.com/reflex-dev/reflex/issues/7456))
+- Assign a value through a state class to update a declared field's default. The default cannot be a Field or Var instance, and must satisfy the field's annotation. A zero-argument callable the annotation does not accept becomes the default factory, validated by calling it once. ([#7461](https://github.com/reflex-dev/reflex/issues/7461))
+
+
## v0.10.0a1 (2026-10-05)
### Breaking Changes
diff --git a/packages/reflex-base/news/+backend-class-assignment.bugfix.md b/packages/reflex-base/news/+backend-class-assignment.bugfix.md
deleted file mode 100644
index ea249d7c8f8..00000000000
--- a/packages/reflex-base/news/+backend-class-assignment.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Assign a value through a state class to update a declared field's default. The default cannot be a Field or Var instance, and must satisfy the field's annotation. A zero-argument callable the annotation does not accept becomes the default factory, validated by calling it once.
diff --git a/packages/reflex-base/news/+backend-var-fstring.bugfix.md b/packages/reflex-base/news/+backend-var-fstring.bugfix.md
deleted file mode 100644
index aa63399fa4c..00000000000
--- a/packages/reflex-base/news/+backend-var-fstring.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Formatting a backend var as a string, e.g. `width=f"{State._size}px"`, now raises `BackendVarFormatError` (a `VarTypeError`) instead of silently embedding the field's repr in the page.
diff --git a/packages/reflex-base/news/+drop-python-310.breaking.md b/packages/reflex-base/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-base/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-base/news/+private-dunder-fields.feature.md b/packages/reflex-base/news/+private-dunder-fields.feature.md
deleted file mode 100644
index 17bc0db0ec6..00000000000
--- a/packages/reflex-base/news/+private-dunder-fields.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-A double-underscore state attribute (a name-mangled `__private` name or a dunder) can now be a backend var by declaring it with an explicit `rx.field()` value, e.g. `__counter: rx.Field[int] = rx.field(0)`. Without one it stays a plain class attribute, like in 0.9.x.
From a0cb4945f66168813c7ede6fd397073bc497cd5e Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 04:54:06 +0000
Subject: [PATCH 06/25] Materialize changelogs for reflex-build-sdk@0.1.0a1,
reflex-components-lucide@1.1.0a1, reflex-release@0.2.0a1
(new-prerelease-minor)
---
packages/reflex-build-sdk/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-lucide/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-lucide/pyproject.toml | 2 +-
packages/reflex-release/CHANGELOG.md | 15 +++++++++++++++
.../news/+directional-lockstep.feature.md | 1 -
.../news/+dispatch-input-limit.bugfix.md | 1 -
.../news/+drop-python-310.breaking.md | 1 -
9 files changed, 30 insertions(+), 6 deletions(-)
delete mode 100644 packages/reflex-build-sdk/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-components-lucide/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-release/news/+directional-lockstep.feature.md
delete mode 100644 packages/reflex-release/news/+dispatch-input-limit.bugfix.md
delete mode 100644 packages/reflex-release/news/+drop-python-310.breaking.md
diff --git a/packages/reflex-build-sdk/CHANGELOG.md b/packages/reflex-build-sdk/CHANGELOG.md
index 84106184409..f010e2b7d46 100644
--- a/packages/reflex-build-sdk/CHANGELOG.md
+++ b/packages/reflex-build-sdk/CHANGELOG.md
@@ -2,6 +2,13 @@
+## v0.1.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.0.5 (2026-09-24)
### Features
diff --git a/packages/reflex-build-sdk/news/+drop-python-310.breaking.md b/packages/reflex-build-sdk/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-build-sdk/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-lucide/CHANGELOG.md b/packages/reflex-components-lucide/CHANGELOG.md
index 092ab38515f..c0890188aa2 100644
--- a/packages/reflex-components-lucide/CHANGELOG.md
+++ b/packages/reflex-components-lucide/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v1.1.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v1.0.4 (2026-08-28)
### Miscellaneous
diff --git a/packages/reflex-components-lucide/news/+drop-python-310.breaking.md b/packages/reflex-components-lucide/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-lucide/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-lucide/pyproject.toml b/packages/reflex-components-lucide/pyproject.toml
index de7695063a1..55f62891fb1 100644
--- a/packages/reflex-components-lucide/pyproject.toml
+++ b/packages/reflex-components-lucide/pyproject.toml
@@ -15,7 +15,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
]
-dependencies = ["reflex-base >= 0.10.0a2.dev0"]
+dependencies = ["reflex-base >= 0.10.0a2"]
[tool.hatch.version]
source = "uv-dynamic-versioning"
diff --git a/packages/reflex-release/CHANGELOG.md b/packages/reflex-release/CHANGELOG.md
index e03e864f1ec..c7537a21c0d 100644
--- a/packages/reflex-release/CHANGELOG.md
+++ b/packages/reflex-release/CHANGELOG.md
@@ -1,3 +1,18 @@
+## v0.2.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+### Features
+
+- Let the early members of a `publish-last` lockstep group release on their own. A `publish-last` member reuses a sibling tag at its version when one exists, and its exact pins are checked against the declared requirement at plan time. ([#7464](https://github.com/reflex-dev/reflex/issues/7464))
+
+### Bug Fixes
+
+- Dispatch release forms keep their per-package checkboxes up to 24 packages, rather than falling back to a free-text field past 19. `workflow_dispatch` has accepted 25 inputs since December 2025. ([#7288](https://github.com/reflex-dev/reflex/issues/7288))
+
+
## v0.1.1 (2026-09-11)
### Bug Fixes
diff --git a/packages/reflex-release/news/+directional-lockstep.feature.md b/packages/reflex-release/news/+directional-lockstep.feature.md
deleted file mode 100644
index a928fe2f243..00000000000
--- a/packages/reflex-release/news/+directional-lockstep.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-Let the early members of a `publish-last` lockstep group release on their own. A `publish-last` member reuses a sibling tag at its version when one exists, and its exact pins are checked against the declared requirement at plan time.
diff --git a/packages/reflex-release/news/+dispatch-input-limit.bugfix.md b/packages/reflex-release/news/+dispatch-input-limit.bugfix.md
deleted file mode 100644
index fb01dc033cb..00000000000
--- a/packages/reflex-release/news/+dispatch-input-limit.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Dispatch release forms keep their per-package checkboxes up to 24 packages, rather than falling back to a free-text field past 19. `workflow_dispatch` has accepted 25 inputs since December 2025.
diff --git a/packages/reflex-release/news/+drop-python-310.breaking.md b/packages/reflex-release/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-release/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
From 7aa2363aca2c972342bcb0f8812d470ee585780b Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 04:59:59 +0000
Subject: [PATCH 07/25] Materialize changelogs for
reflex-components-sonner@0.10.0a1, reflex-hosting-cli@0.2.0a1
(new-prerelease-minor)
---
.../reflex-components-sonner/CHANGELOG.md | 7 ++++++
.../news/+drop-python-310.breaking.md | 1 -
.../reflex-components-sonner/pyproject.toml | 4 ++--
packages/reflex-hosting-cli/CHANGELOG.md | 23 +++++++++++++++++++
.../news/+drop-python-310.breaking.md | 1 -
.../news/+secrets-update-success.bugfix.md | 1 -
.../reflex-hosting-cli/news/7207.breaking.md | 1 -
.../reflex-hosting-cli/news/7207.bugfix.md | 1 -
packages/reflex-hosting-cli/news/7207.misc.md | 1 -
.../reflex-hosting-cli/news/7295.bugfix.md | 1 -
.../reflex-hosting-cli/news/7298.bugfix.md | 1 -
.../reflex-hosting-cli/news/7321.bugfix.md | 1 -
.../reflex-hosting-cli/news/7333.bugfix.md | 1 -
.../reflex-hosting-cli/news/7351.bugfix.md | 1 -
.../reflex-hosting-cli/news/7355.bugfix.md | 1 -
packages/reflex-hosting-cli/pyproject.toml | 2 +-
16 files changed, 33 insertions(+), 15 deletions(-)
delete mode 100644 packages/reflex-components-sonner/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-hosting-cli/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-hosting-cli/news/+secrets-update-success.bugfix.md
delete mode 100644 packages/reflex-hosting-cli/news/7207.breaking.md
delete mode 100644 packages/reflex-hosting-cli/news/7207.bugfix.md
delete mode 100644 packages/reflex-hosting-cli/news/7207.misc.md
delete mode 100644 packages/reflex-hosting-cli/news/7295.bugfix.md
delete mode 100644 packages/reflex-hosting-cli/news/7298.bugfix.md
delete mode 100644 packages/reflex-hosting-cli/news/7321.bugfix.md
delete mode 100644 packages/reflex-hosting-cli/news/7333.bugfix.md
delete mode 100644 packages/reflex-hosting-cli/news/7351.bugfix.md
delete mode 100644 packages/reflex-hosting-cli/news/7355.bugfix.md
diff --git a/packages/reflex-components-sonner/CHANGELOG.md b/packages/reflex-components-sonner/CHANGELOG.md
index 502b798252a..b67ad4b2fe2 100644
--- a/packages/reflex-components-sonner/CHANGELOG.md
+++ b/packages/reflex-components-sonner/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.9.4 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-sonner/news/+drop-python-310.breaking.md b/packages/reflex-components-sonner/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-sonner/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-sonner/pyproject.toml b/packages/reflex-components-sonner/pyproject.toml
index 8f75e1e6232..5693f5cf6b1 100644
--- a/packages/reflex-components-sonner/pyproject.toml
+++ b/packages/reflex-components-sonner/pyproject.toml
@@ -16,8 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-lucide >= 1.0.5.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-lucide >= 1.1.0a1",
]
[tool.hatch.version]
diff --git a/packages/reflex-hosting-cli/CHANGELOG.md b/packages/reflex-hosting-cli/CHANGELOG.md
index 340462f58cf..e00699f22b7 100644
--- a/packages/reflex-hosting-cli/CHANGELOG.md
+++ b/packages/reflex-hosting-cli/CHANGELOG.md
@@ -1,3 +1,26 @@
+## v0.2.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Some `reflex cloud` commands changed what they report. A refused request now exits non-zero rather than printing a `"... failed: ..."` line and exiting 0, and `--json` writes no document on that path; `apps stop`, `apps start` and `apps delete` are the ones most likely to be scripted against, and they now report their own outcome rather than echoing the server's sentence. `vmtypes` and `regions` answered a failed request with an empty listing and exit 0, which a script could not tell from a control plane that offers neither; they exit non-zero now. `apps history --json` replaces `hostname` with the deployment's `url`, reports `vm type` as the machine's name rather than an object, and reports `timestamp` as an ISO 8601 string with an offset; `apps inspect --json` drops `hostname` from `latest_deployment` the same way, the URL carrying it already. `create-token --json` replaces `expires_in_days` with `expires_at`, an ISO 8601 string or `null`, carrying the expiry the server applied rather than the duration that was asked for. `apps logs` drops its inert `--cursor` option and its `--json` document returns every line in the window rather than one page. `project role-permissions` lists permission names rather than objects. `reflex deploy` now requires a control plane that signs upload URLs; the multipart fallback for older ones is gone, and with it the "payload is too large (over 100MB)" hint, which only that path could produce. And `apps status --watch --json` reports `"success": null` when the watch stopped before the deployment ended -- it is still running, and the command did not see how it finished -- rather than answering `true` or `false` for something it does not know. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+### Bug Fixes
+
+- `reflex cloud` reports a refusal as the sentence the API wrote rather than a message of its own, and an expired token now says to run `reflex login` wherever it turns up — not only where a command started by authenticating. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
+- `reflex cloud apps delete` now exits non-zero when the app ID is not found. ([#7295](https://github.com/reflex-dev/reflex/issues/7295))
+- With `--no-interactive`, a rejected access token now fails right away with the same message `reflex cloud whoami` gives, instead of starting the browser login. ([#7298](https://github.com/reflex-dev/reflex/issues/7298))
+- Preserve a different stored access token when authentication rejects an outdated or explicitly supplied token. ([#7321](https://github.com/reflex-dev/reflex/issues/7321))
+- `reflex deploy` now consistently shows the "Built with Reflex" badge on apps deployed on the free tier, including apps built with earlier reflex releases. Paid plans can still hide it with `show_built_with_reflex=False`. ([#7333](https://github.com/reflex-dev/reflex/issues/7333))
+- `reflex cloud apps list`, `apps history` and `apps inspect` keep app names and app and deployment IDs whole on one line, so you can copy them from a normal-width terminal. `apps list` and `apps history` show fewer columns; `--json` still returns every field. `apps inspect` shows one field per row. Tables no longer draw cell borders. ([#7351](https://github.com/reflex-dev/reflex/issues/7351))
+- `reflex cloud secrets update` now prints a success line naming the keys it set and whether the app is rebooting, like `secrets delete` already did. Only key names are printed; values are never logged. ([#7352](https://github.com/reflex-dev/reflex/issues/7352))
+- Fail `reflex deploy` before building when an explicitly requested project does not exist or does not own the selected app. Accept equivalent UUID spellings, including uppercase and unhyphenated project IDs. ([#7355](https://github.com/reflex-dev/reflex/issues/7355))
+
+### Miscellaneous
+
+- `reflex-hosting-cli` now talks to Reflex Build through `reflex-build-sdk` rather than its own HTTP layer, so every command shares the SDK's retries, timeouts and typed errors. While the SDK is pre-1.0, where any release may change its API, the requirement is capped to the single patch line the CLI was built against, so upgrade `reflex-hosting-cli` to move to a newer SDK rather than upgrading the SDK on its own. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
+
+
## v0.1.72 (2026-09-11)
### Breaking Changes
diff --git a/packages/reflex-hosting-cli/news/+drop-python-310.breaking.md b/packages/reflex-hosting-cli/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-hosting-cli/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-hosting-cli/news/+secrets-update-success.bugfix.md b/packages/reflex-hosting-cli/news/+secrets-update-success.bugfix.md
deleted file mode 100644
index 70179086b24..00000000000
--- a/packages/reflex-hosting-cli/news/+secrets-update-success.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex cloud secrets update` now prints a success line naming the keys it set and whether the app is rebooting, like `secrets delete` already did. Only key names are printed; values are never logged.
diff --git a/packages/reflex-hosting-cli/news/7207.breaking.md b/packages/reflex-hosting-cli/news/7207.breaking.md
deleted file mode 100644
index 551fa32a36f..00000000000
--- a/packages/reflex-hosting-cli/news/7207.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Some `reflex cloud` commands changed what they report. A refused request now exits non-zero rather than printing a `"... failed: ..."` line and exiting 0, and `--json` writes no document on that path; `apps stop`, `apps start` and `apps delete` are the ones most likely to be scripted against, and they now report their own outcome rather than echoing the server's sentence. `vmtypes` and `regions` answered a failed request with an empty listing and exit 0, which a script could not tell from a control plane that offers neither; they exit non-zero now. `apps history --json` replaces `hostname` with the deployment's `url`, reports `vm type` as the machine's name rather than an object, and reports `timestamp` as an ISO 8601 string with an offset; `apps inspect --json` drops `hostname` from `latest_deployment` the same way, the URL carrying it already. `create-token --json` replaces `expires_in_days` with `expires_at`, an ISO 8601 string or `null`, carrying the expiry the server applied rather than the duration that was asked for. `apps logs` drops its inert `--cursor` option and its `--json` document returns every line in the window rather than one page. `project role-permissions` lists permission names rather than objects. `reflex deploy` now requires a control plane that signs upload URLs; the multipart fallback for older ones is gone, and with it the "payload is too large (over 100MB)" hint, which only that path could produce. And `apps status --watch --json` reports `"success": null` when the watch stopped before the deployment ended -- it is still running, and the command did not see how it finished -- rather than answering `true` or `false` for something it does not know.
diff --git a/packages/reflex-hosting-cli/news/7207.bugfix.md b/packages/reflex-hosting-cli/news/7207.bugfix.md
deleted file mode 100644
index 6d1a1bb4f56..00000000000
--- a/packages/reflex-hosting-cli/news/7207.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex cloud` reports a refusal as the sentence the API wrote rather than a message of its own, and an expired token now says to run `reflex login` wherever it turns up — not only where a command started by authenticating.
diff --git a/packages/reflex-hosting-cli/news/7207.misc.md b/packages/reflex-hosting-cli/news/7207.misc.md
deleted file mode 100644
index 598864c5df2..00000000000
--- a/packages/reflex-hosting-cli/news/7207.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex-hosting-cli` now talks to Reflex Build through `reflex-build-sdk` rather than its own HTTP layer, so every command shares the SDK's retries, timeouts and typed errors. While the SDK is pre-1.0, where any release may change its API, the requirement is capped to the single patch line the CLI was built against, so upgrade `reflex-hosting-cli` to move to a newer SDK rather than upgrading the SDK on its own.
diff --git a/packages/reflex-hosting-cli/news/7295.bugfix.md b/packages/reflex-hosting-cli/news/7295.bugfix.md
deleted file mode 100644
index 90f0a1a5aac..00000000000
--- a/packages/reflex-hosting-cli/news/7295.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex cloud apps delete` now exits non-zero when the app ID is not found.
diff --git a/packages/reflex-hosting-cli/news/7298.bugfix.md b/packages/reflex-hosting-cli/news/7298.bugfix.md
deleted file mode 100644
index 7b6017db7ea..00000000000
--- a/packages/reflex-hosting-cli/news/7298.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-With `--no-interactive`, a rejected access token now fails right away with the same message `reflex cloud whoami` gives, instead of starting the browser login.
diff --git a/packages/reflex-hosting-cli/news/7321.bugfix.md b/packages/reflex-hosting-cli/news/7321.bugfix.md
deleted file mode 100644
index e691e12eeea..00000000000
--- a/packages/reflex-hosting-cli/news/7321.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Preserve a different stored access token when authentication rejects an outdated or explicitly supplied token.
diff --git a/packages/reflex-hosting-cli/news/7333.bugfix.md b/packages/reflex-hosting-cli/news/7333.bugfix.md
deleted file mode 100644
index 0983945c430..00000000000
--- a/packages/reflex-hosting-cli/news/7333.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex deploy` now consistently shows the "Built with Reflex" badge on apps deployed on the free tier, including apps built with earlier reflex releases. Paid plans can still hide it with `show_built_with_reflex=False`.
diff --git a/packages/reflex-hosting-cli/news/7351.bugfix.md b/packages/reflex-hosting-cli/news/7351.bugfix.md
deleted file mode 100644
index 7f4269f32d3..00000000000
--- a/packages/reflex-hosting-cli/news/7351.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex cloud apps list`, `apps history` and `apps inspect` keep app names and app and deployment IDs whole on one line, so you can copy them from a normal-width terminal. `apps list` and `apps history` show fewer columns; `--json` still returns every field. `apps inspect` shows one field per row. Tables no longer draw cell borders.
diff --git a/packages/reflex-hosting-cli/news/7355.bugfix.md b/packages/reflex-hosting-cli/news/7355.bugfix.md
deleted file mode 100644
index 1f5b1192704..00000000000
--- a/packages/reflex-hosting-cli/news/7355.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Fail `reflex deploy` before building when an explicitly requested project does not exist or does not own the selected app. Accept equivalent UUID spellings, including uppercase and unhyphenated project IDs.
diff --git a/packages/reflex-hosting-cli/pyproject.toml b/packages/reflex-hosting-cli/pyproject.toml
index 8dbada456db..a07bacefcce 100644
--- a/packages/reflex-hosting-cli/pyproject.toml
+++ b/packages/reflex-hosting-cli/pyproject.toml
@@ -35,7 +35,7 @@ dependencies = [
# workspace's dev build until the 0.1.0 alpha publishes and materialization
# lifts it; the cap admits 0.1.0 and the ``0.1.1.devN`` builds that follow
# its tag, but not 0.1.1 itself.
- "reflex-build-sdk[httpx] >=0.0.6.dev0,<0.1.1.post,!=0.1.1",
+ "reflex-build-sdk[httpx] >=0.1.0a1,<0.1.1.post,!=0.1.1",
"rich >=13,<16",
]
From ff2995c50a99c19cb940e1e40d9bd0d045e52f0c Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 05:11:03 +0000
Subject: [PATCH 08/25] Materialize changelogs for
reflex-components-core@0.10.0a2, reflex-components-gridjs@0.10.0a2,
reflex-components-moment@0.10.0a2 (continued-prerelease)
---
packages/reflex-components-core/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-core/pyproject.toml | 6 +++---
packages/reflex-components-gridjs/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-gridjs/pyproject.toml | 2 +-
packages/reflex-components-moment/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-moment/pyproject.toml | 2 +-
9 files changed, 26 insertions(+), 8 deletions(-)
delete mode 100644 packages/reflex-components-core/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-components-gridjs/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-components-moment/news/+drop-python-310.breaking.md
diff --git a/packages/reflex-components-core/CHANGELOG.md b/packages/reflex-components-core/CHANGELOG.md
index 320472abbfd..1220de24868 100644
--- a/packages/reflex-components-core/CHANGELOG.md
+++ b/packages/reflex-components-core/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Features
diff --git a/packages/reflex-components-core/news/+drop-python-310.breaking.md b/packages/reflex-components-core/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-core/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-core/pyproject.toml b/packages/reflex-components-core/pyproject.toml
index 084c125aa48..f55e890aa8e 100644
--- a/packages/reflex-components-core/pyproject.toml
+++ b/packages/reflex-components-core/pyproject.toml
@@ -16,9 +16,9 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-lucide >= 1.0.5.dev0",
- "reflex-components-sonner >= 0.9.5.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-lucide >= 1.1.0a1",
+ "reflex-components-sonner >= 0.10.0a1",
"python_multipart >= 0.0.21",
"starlette >= 0.47.0",
"typing_extensions >= 4.0.0",
diff --git a/packages/reflex-components-gridjs/CHANGELOG.md b/packages/reflex-components-gridjs/CHANGELOG.md
index 2e103837000..dcc7e6a2d8e 100644
--- a/packages/reflex-components-gridjs/CHANGELOG.md
+++ b/packages/reflex-components-gridjs/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Bug Fixes
diff --git a/packages/reflex-components-gridjs/news/+drop-python-310.breaking.md b/packages/reflex-components-gridjs/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-gridjs/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-gridjs/pyproject.toml b/packages/reflex-components-gridjs/pyproject.toml
index 1694f726e28..4cf6235f725 100644
--- a/packages/reflex-components-gridjs/pyproject.toml
+++ b/packages/reflex-components-gridjs/pyproject.toml
@@ -15,7 +15,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
]
-dependencies = ["reflex-base >= 0.10.0a2.dev0"]
+dependencies = ["reflex-base >= 0.10.0a2"]
[tool.hatch.version]
source = "uv-dynamic-versioning"
diff --git a/packages/reflex-components-moment/CHANGELOG.md b/packages/reflex-components-moment/CHANGELOG.md
index 6e540d8779d..fc4edc48ff0 100644
--- a/packages/reflex-components-moment/CHANGELOG.md
+++ b/packages/reflex-components-moment/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Miscellaneous
diff --git a/packages/reflex-components-moment/news/+drop-python-310.breaking.md b/packages/reflex-components-moment/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-moment/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-moment/pyproject.toml b/packages/reflex-components-moment/pyproject.toml
index 1763599bb26..2f5e06744f2 100644
--- a/packages/reflex-components-moment/pyproject.toml
+++ b/packages/reflex-components-moment/pyproject.toml
@@ -15,7 +15,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
]
-dependencies = ["reflex-base >= 0.10.0a2.dev0"]
+dependencies = ["reflex-base >= 0.10.0a2"]
[tool.hatch.version]
source = "uv-dynamic-versioning"
From 15057ac296a92360bc9c4103aeb953a9cd0ca117 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 05:16:56 +0000
Subject: [PATCH 09/25] Materialize changelogs for
reflex-components-dataeditor@0.10.0a1,
reflex-components-react-player@0.10.0a1 (new-prerelease-minor)
---
packages/reflex-components-dataeditor/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-dataeditor/pyproject.toml | 4 ++--
packages/reflex-components-react-player/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-react-player/pyproject.toml | 4 ++--
6 files changed, 18 insertions(+), 6 deletions(-)
delete mode 100644 packages/reflex-components-dataeditor/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-components-react-player/news/+drop-python-310.breaking.md
diff --git a/packages/reflex-components-dataeditor/CHANGELOG.md b/packages/reflex-components-dataeditor/CHANGELOG.md
index 8da75734d11..a208c26e049 100644
--- a/packages/reflex-components-dataeditor/CHANGELOG.md
+++ b/packages/reflex-components-dataeditor/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.9.3.post1 (2026-10-06)
### Bug Fixes
diff --git a/packages/reflex-components-dataeditor/news/+drop-python-310.breaking.md b/packages/reflex-components-dataeditor/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-dataeditor/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-dataeditor/pyproject.toml b/packages/reflex-components-dataeditor/pyproject.toml
index d13eb7fdb16..6c45e45b6a2 100644
--- a/packages/reflex-components-dataeditor/pyproject.toml
+++ b/packages/reflex-components-dataeditor/pyproject.toml
@@ -16,8 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-core >= 0.10.0a2.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-core >= 0.10.0a2",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-react-player/CHANGELOG.md b/packages/reflex-components-react-player/CHANGELOG.md
index 47b7c35aaee..daa780ef327 100644
--- a/packages/reflex-components-react-player/CHANGELOG.md
+++ b/packages/reflex-components-react-player/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.9.2 (2026-08-28)
### Miscellaneous
diff --git a/packages/reflex-components-react-player/news/+drop-python-310.breaking.md b/packages/reflex-components-react-player/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-react-player/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-react-player/pyproject.toml b/packages/reflex-components-react-player/pyproject.toml
index 0b5a30aa63b..76e62459e2a 100644
--- a/packages/reflex-components-react-player/pyproject.toml
+++ b/packages/reflex-components-react-player/pyproject.toml
@@ -16,8 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-core >= 0.10.0a2.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-core >= 0.10.0a2",
]
[tool.hatch.version]
From da793054878364e49d6a29ca28953b7ad45f3501 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 05:22:36 +0000
Subject: [PATCH 10/25] Materialize changelogs for
reflex-components-plotly@0.10.0a2, reflex-components-radix@0.10.0a2,
reflex-components-recharts@0.10.0a2 (continued-prerelease)
---
packages/reflex-components-plotly/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-plotly/pyproject.toml | 4 ++--
packages/reflex-components-radix/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-radix/pyproject.toml | 6 +++---
packages/reflex-components-recharts/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-recharts/pyproject.toml | 4 ++--
9 files changed, 28 insertions(+), 10 deletions(-)
delete mode 100644 packages/reflex-components-plotly/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-components-radix/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-components-recharts/news/+drop-python-310.breaking.md
diff --git a/packages/reflex-components-plotly/CHANGELOG.md b/packages/reflex-components-plotly/CHANGELOG.md
index f9088f85aab..9babbf4713a 100644
--- a/packages/reflex-components-plotly/CHANGELOG.md
+++ b/packages/reflex-components-plotly/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Bug Fixes
diff --git a/packages/reflex-components-plotly/news/+drop-python-310.breaking.md b/packages/reflex-components-plotly/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-plotly/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-plotly/pyproject.toml b/packages/reflex-components-plotly/pyproject.toml
index 8c4205fdc43..a1d06696726 100644
--- a/packages/reflex-components-plotly/pyproject.toml
+++ b/packages/reflex-components-plotly/pyproject.toml
@@ -18,8 +18,8 @@ classifiers = [
dependencies = [
# The unversioned "mergician" import resolves against the pin in
# reflex-base's PackageJson.DEPENDENCIES.
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-core >= 0.10.0a2.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-core >= 0.10.0a2",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-radix/CHANGELOG.md b/packages/reflex-components-radix/CHANGELOG.md
index 838444ae563..eb70b44ecb2 100644
--- a/packages/reflex-components-radix/CHANGELOG.md
+++ b/packages/reflex-components-radix/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Bug Fixes
diff --git a/packages/reflex-components-radix/news/+drop-python-310.breaking.md b/packages/reflex-components-radix/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-radix/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-radix/pyproject.toml b/packages/reflex-components-radix/pyproject.toml
index 9269e536fa5..79b597983e1 100644
--- a/packages/reflex-components-radix/pyproject.toml
+++ b/packages/reflex-components-radix/pyproject.toml
@@ -16,9 +16,9 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-core >= 0.10.0a2.dev0",
- "reflex-components-lucide >= 1.0.5.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-core >= 0.10.0a2",
+ "reflex-components-lucide >= 1.1.0a1",
]
[tool.hatch.version]
diff --git a/packages/reflex-components-recharts/CHANGELOG.md b/packages/reflex-components-recharts/CHANGELOG.md
index b2fdf9e9027..0bfa3a795b4 100644
--- a/packages/reflex-components-recharts/CHANGELOG.md
+++ b/packages/reflex-components-recharts/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Bug Fixes
diff --git a/packages/reflex-components-recharts/news/+drop-python-310.breaking.md b/packages/reflex-components-recharts/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-recharts/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-recharts/pyproject.toml b/packages/reflex-components-recharts/pyproject.toml
index e6d03269478..ce2e3d5877a 100644
--- a/packages/reflex-components-recharts/pyproject.toml
+++ b/packages/reflex-components-recharts/pyproject.toml
@@ -16,8 +16,8 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-core >= 0.10.0a2.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-core >= 0.10.0a2",
]
[tool.hatch.version]
From cf7610fcdc41709a36b74f507e7609e2dcc6f47e Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 05:26:27 +0000
Subject: [PATCH 11/25] Materialize changelogs for
reflex-components-code@0.10.0a2 (continued-prerelease)
---
packages/reflex-components-code/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-code/pyproject.toml | 8 ++++----
3 files changed, 11 insertions(+), 5 deletions(-)
delete mode 100644 packages/reflex-components-code/news/+drop-python-310.breaking.md
diff --git a/packages/reflex-components-code/CHANGELOG.md b/packages/reflex-components-code/CHANGELOG.md
index 81b4c746fe6..06a6969727f 100644
--- a/packages/reflex-components-code/CHANGELOG.md
+++ b/packages/reflex-components-code/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Miscellaneous
diff --git a/packages/reflex-components-code/news/+drop-python-310.breaking.md b/packages/reflex-components-code/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-code/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-code/pyproject.toml b/packages/reflex-components-code/pyproject.toml
index fad8c019c48..a5890b2eea0 100644
--- a/packages/reflex-components-code/pyproject.toml
+++ b/packages/reflex-components-code/pyproject.toml
@@ -16,10 +16,10 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-core >= 0.10.0a2.dev0",
- "reflex-components-lucide >= 1.0.5.dev0",
- "reflex-components-radix >= 0.10.0a2.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-core >= 0.10.0a2",
+ "reflex-components-lucide >= 1.1.0a1",
+ "reflex-components-radix >= 0.10.0a2",
]
[tool.hatch.version]
From a8a21f538f3de99fb51bc450fa593fcde6dc354f Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 05:31:59 +0000
Subject: [PATCH 12/25] Materialize changelogs for
reflex-components-markdown@0.10.0a2 (continued-prerelease)
---
packages/reflex-components-markdown/CHANGELOG.md | 7 +++++++
.../news/+drop-python-310.breaking.md | 1 -
packages/reflex-components-markdown/pyproject.toml | 8 ++++----
3 files changed, 11 insertions(+), 5 deletions(-)
delete mode 100644 packages/reflex-components-markdown/news/+drop-python-310.breaking.md
diff --git a/packages/reflex-components-markdown/CHANGELOG.md b/packages/reflex-components-markdown/CHANGELOG.md
index ed2e4366ad4..62756042c7a 100644
--- a/packages/reflex-components-markdown/CHANGELOG.md
+++ b/packages/reflex-components-markdown/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Bug Fixes
diff --git a/packages/reflex-components-markdown/news/+drop-python-310.breaking.md b/packages/reflex-components-markdown/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-components-markdown/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-components-markdown/pyproject.toml b/packages/reflex-components-markdown/pyproject.toml
index 83f5802c699..580df38789f 100644
--- a/packages/reflex-components-markdown/pyproject.toml
+++ b/packages/reflex-components-markdown/pyproject.toml
@@ -16,10 +16,10 @@ classifiers = [
"Programming Language :: Python :: 3.15",
]
dependencies = [
- "reflex-base >= 0.10.0a2.dev0",
- "reflex-components-code >= 0.10.0a2.dev0",
- "reflex-components-core >= 0.10.0a2.dev0",
- "reflex-components-radix >= 0.10.0a2.dev0",
+ "reflex-base >= 0.10.0a2",
+ "reflex-components-code >= 0.10.0a2",
+ "reflex-components-core >= 0.10.0a2",
+ "reflex-components-radix >= 0.10.0a2",
]
[tool.hatch.version]
From 82ba92ea64cd7f5331ed44e681c2e93a1f570f7a Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 05:35:48 +0000
Subject: [PATCH 13/25] Materialize changelogs for reflex@0.10.0a2
(continued-prerelease)
---
CHANGELOG.md | 20 +++++++++++++++
news/+backend-class-assignment.bugfix.md | 1 -
news/+drop-python-310.breaking.md | 1 -
news/+hydrate-client-storage.bugfix.md | 1 -
news/+hydrate-computed-var-changes.bugfix.md | 1 -
news/+private-names-assignable.bugfix.md | 1 -
news/+python311-sibling-floors.misc.md | 1 -
news/+refresh-dependencies.misc.md | 1 -
news/7359.bugfix.md | 1 -
pyproject.toml | 26 ++++++++++----------
10 files changed, 33 insertions(+), 21 deletions(-)
delete mode 100644 news/+backend-class-assignment.bugfix.md
delete mode 100644 news/+drop-python-310.breaking.md
delete mode 100644 news/+hydrate-client-storage.bugfix.md
delete mode 100644 news/+hydrate-computed-var-changes.bugfix.md
delete mode 100644 news/+private-names-assignable.bugfix.md
delete mode 100644 news/+python311-sibling-floors.misc.md
delete mode 100644 news/+refresh-dependencies.misc.md
delete mode 100644 news/7359.bugfix.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d06cfb18cab..86d112ccd55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,23 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Drop support for Python 3.10, which reaches end of life in October 2026. Reflex now requires Python 3.11 or newer. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+### Bug Fixes
+
+- `AppHarness` now forgets the states of every module of the app's package when it stops, not only those of the app module, so a state defined elsewhere in the app (for example one using `rx.dynamic`) no longer breaks the next app started in the same test process. ([#7359](https://github.com/reflex-dev/reflex/issues/7359))
+- Deliver changes to client-storage and other state vars made by computed vars during hydration to the browser. ([#7460](https://github.com/reflex-dev/reflex/issues/7460))
+- Prevent hydration from persisting client-storage defaults. ([#7460](https://github.com/reflex-dev/reflex/issues/7460))
+- Configure per-component defaults in `ComponentState.get_component` with assignments such as `cls.count = 10`. Reset restores the last configured default. Defaults are no longer part of the saved-state schema, so changing one keeps state saved by this release or later loadable. Browser storage vars keep their storage settings when a factory is assigned, and declared factories are honored when compiled and reset. ([#7461](https://github.com/reflex-dev/reflex/issues/7461))
+- Assigning a double-underscore private attribute on a state (`self.__counter = 1`) from a mixin, a base, or a class whose name starts with an underscore no longer raises `SetUndefinedStateVarError` in dev mode. Private names not explicitly declared with `rx.field()` are plain Python attributes: vars do not update in response to them. ([#7465](https://github.com/reflex-dev/reflex/issues/7465))
+
+### Miscellaneous
+
+- Allow wrapt 2.4 and 2.5. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
+- Require sibling package versions from the Python 3.11 release train. ([#7464](https://github.com/reflex-dev/reflex/issues/7464))
+
+
## v0.10.0a1 (2026-10-05)
### Breaking Changes
diff --git a/news/+backend-class-assignment.bugfix.md b/news/+backend-class-assignment.bugfix.md
deleted file mode 100644
index 5c904bd3fdb..00000000000
--- a/news/+backend-class-assignment.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Configure per-component defaults in `ComponentState.get_component` with assignments such as `cls.count = 10`. Reset restores the last configured default. Defaults are no longer part of the saved-state schema, so changing one keeps state saved by this release or later loadable. Browser storage vars keep their storage settings when a factory is assigned, and declared factories are honored when compiled and reset.
diff --git a/news/+drop-python-310.breaking.md b/news/+drop-python-310.breaking.md
deleted file mode 100644
index e2acb7b82bf..00000000000
--- a/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Drop support for Python 3.10, which reaches end of life in October 2026. Reflex now requires Python 3.11 or newer.
diff --git a/news/+hydrate-client-storage.bugfix.md b/news/+hydrate-client-storage.bugfix.md
deleted file mode 100644
index 2d24066f12b..00000000000
--- a/news/+hydrate-client-storage.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Prevent hydration from persisting client-storage defaults.
diff --git a/news/+hydrate-computed-var-changes.bugfix.md b/news/+hydrate-computed-var-changes.bugfix.md
deleted file mode 100644
index 58d942a6329..00000000000
--- a/news/+hydrate-computed-var-changes.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Deliver changes to client-storage and other state vars made by computed vars during hydration to the browser.
diff --git a/news/+private-names-assignable.bugfix.md b/news/+private-names-assignable.bugfix.md
deleted file mode 100644
index db341c49ddc..00000000000
--- a/news/+private-names-assignable.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Assigning a double-underscore private attribute on a state (`self.__counter = 1`) from a mixin, a base, or a class whose name starts with an underscore no longer raises `SetUndefinedStateVarError` in dev mode. Private names not explicitly declared with `rx.field()` are plain Python attributes: vars do not update in response to them.
diff --git a/news/+python311-sibling-floors.misc.md b/news/+python311-sibling-floors.misc.md
deleted file mode 100644
index 68a6cb67b61..00000000000
--- a/news/+python311-sibling-floors.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Require sibling package versions from the Python 3.11 release train.
diff --git a/news/+refresh-dependencies.misc.md b/news/+refresh-dependencies.misc.md
deleted file mode 100644
index 7e14cd88db4..00000000000
--- a/news/+refresh-dependencies.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-Allow wrapt 2.4 and 2.5.
diff --git a/news/7359.bugfix.md b/news/7359.bugfix.md
deleted file mode 100644
index 7187943ee80..00000000000
--- a/news/7359.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`AppHarness` now forgets the states of every module of the app's package when it stops, not only those of the app module, so a state defined elsewhere in the app (for example one using `rx.dynamic`) no longer breaks the next app started in the same test process.
diff --git a/pyproject.toml b/pyproject.toml
index e077dc02392..7474b25c80c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -33,20 +33,20 @@ dependencies = [
"typing_extensions >=4.13.0",
"wrapt >=1.17.0,<2.6",
"reflex-base >= 0.10.0a2.dev0",
- "reflex-components-code >= 0.10.0a2.dev0",
- "reflex-components-core >= 0.10.0a2.dev0",
- "reflex-components-dataeditor >= 0.9.3.post2.dev0",
- "reflex-components-gridjs >= 0.10.0a2.dev0",
- "reflex-components-lucide >= 1.0.5.dev0",
- "reflex-components-markdown >= 0.10.0a2.dev0",
- "reflex-components-moment >= 0.10.0a2.dev0",
- "reflex-components-plotly >= 0.10.0a2.dev0",
- "reflex-components-radix >= 0.10.0a2.dev0",
- "reflex-components-react-player >= 0.9.3.dev0",
- "reflex-components-recharts >= 0.10.0a2.dev0",
- "reflex-components-sonner >= 0.9.5.dev0",
+ "reflex-components-code >= 0.10.0a2",
+ "reflex-components-core >= 0.10.0a2",
+ "reflex-components-dataeditor >= 0.10.0a1",
+ "reflex-components-gridjs >= 0.10.0a2",
+ "reflex-components-lucide >= 1.1.0a1",
+ "reflex-components-markdown >= 0.10.0a2",
+ "reflex-components-moment >= 0.10.0a2",
+ "reflex-components-plotly >= 0.10.0a2",
+ "reflex-components-radix >= 0.10.0a2",
+ "reflex-components-react-player >= 0.10.0a1",
+ "reflex-components-recharts >= 0.10.0a2",
+ "reflex-components-sonner >= 0.10.0a1",
# 0.1.73a1 predates the Python 3.11 train; the floor lifts to the next alpha.
- "reflex-hosting-cli >= 0.1.72.post2.dev0, != 0.1.73a1",
+ "reflex-hosting-cli >= 0.2.0a1, != 0.1.73a1",
]
classifiers = [
From 3a211ff424a56f4b5086c51f7ba8deadbaac1379 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 05:49:35 +0000
Subject: [PATCH 14/25] Materialize changelogs for reflex-docgen@0.10.0a2
(continued-prerelease)
---
packages/reflex-docgen/CHANGELOG.md | 7 +++++++
packages/reflex-docgen/news/+drop-python-310.breaking.md | 1 -
packages/reflex-docgen/pyproject.toml | 2 +-
3 files changed, 8 insertions(+), 2 deletions(-)
delete mode 100644 packages/reflex-docgen/news/+drop-python-310.breaking.md
diff --git a/packages/reflex-docgen/CHANGELOG.md b/packages/reflex-docgen/CHANGELOG.md
index 08a184ebf46..f7f7f82c5a4 100644
--- a/packages/reflex-docgen/CHANGELOG.md
+++ b/packages/reflex-docgen/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a2 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+
+
## v0.10.0a1 (2026-10-05)
### Bug Fixes
diff --git a/packages/reflex-docgen/news/+drop-python-310.breaking.md b/packages/reflex-docgen/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-docgen/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-docgen/pyproject.toml b/packages/reflex-docgen/pyproject.toml
index 7ff21af1134..25a3ee3086e 100644
--- a/packages/reflex-docgen/pyproject.toml
+++ b/packages/reflex-docgen/pyproject.toml
@@ -19,7 +19,7 @@ dependencies = [
"griffelib >= 2.0.1",
"mistletoe >= 1.4.0",
"pyyaml >= 6.0.3",
- "reflex >= 0.10.0a2.dev0",
+ "reflex >= 0.10.0a2",
"typing-inspection>=0.4.2",
]
From e211584d32780cd342dd2d6dd3e159290af09731 Mon Sep 17 00:00:00 2001
From: Claude
Date: Wed, 7 Oct 2026 05:51:50 +0000
Subject: [PATCH 15/25] Add news fragment for reflex-otel's Python 3.10 drop
reflex-otel raised its floor to Python 3.11 in #7449 without a news
fragment, so the release tooling had nothing to release it with. Add the
same fragment the other packages got, and a news/.gitkeep so the directory
survives materialization.
Co-Authored-By: Claude Fable 5.1
Claude-Session: https://claude.ai/code/session_011qWgGrSKMqztQtSRWBP7KK
---
packages/reflex-otel/news/+drop-python-310.breaking.md | 1 +
packages/reflex-otel/news/.gitkeep | 0
2 files changed, 1 insertion(+)
create mode 100644 packages/reflex-otel/news/+drop-python-310.breaking.md
create mode 100644 packages/reflex-otel/news/.gitkeep
diff --git a/packages/reflex-otel/news/+drop-python-310.breaking.md b/packages/reflex-otel/news/+drop-python-310.breaking.md
new file mode 100644
index 00000000000..4d55e54b6e6
--- /dev/null
+++ b/packages/reflex-otel/news/+drop-python-310.breaking.md
@@ -0,0 +1 @@
+Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-otel/news/.gitkeep b/packages/reflex-otel/news/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
From 3f8102678d3f3910e079156db4027e64b3458a7c Mon Sep 17 00:00:00 2001
From: Claude
Date: Wed, 7 Oct 2026 06:01:59 +0000
Subject: [PATCH 16/25] Require reflex-base 0.10 in reflex-otel
Floor reflex-otel on the 0.10.0a2 alpha already published from this
prerelease train, so its own alpha ships against the train rather than
0.9.x. A prerelease floor is shippable for an alpha release; the final
release lifts it to the first published 0.10 final.
Co-Authored-By: Claude Fable 5.1
Claude-Session: https://claude.ai/code/session_011qWgGrSKMqztQtSRWBP7KK
---
packages/reflex-otel/news/+reflex-base-0-10.breaking.md | 1 +
packages/reflex-otel/pyproject.toml | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 packages/reflex-otel/news/+reflex-base-0-10.breaking.md
diff --git a/packages/reflex-otel/news/+reflex-base-0-10.breaking.md b/packages/reflex-otel/news/+reflex-base-0-10.breaking.md
new file mode 100644
index 00000000000..15faae1789e
--- /dev/null
+++ b/packages/reflex-otel/news/+reflex-base-0-10.breaking.md
@@ -0,0 +1 @@
+Require `reflex-base` 0.10 or newer.
diff --git a/packages/reflex-otel/pyproject.toml b/packages/reflex-otel/pyproject.toml
index 4a86420cbc9..b6e64995fef 100644
--- a/packages/reflex-otel/pyproject.toml
+++ b/packages/reflex-otel/pyproject.toml
@@ -19,7 +19,7 @@ dependencies = [
"opentelemetry-api >=1.30.0,<2.0",
"opentelemetry-instrumentation >=0.49b0,<1.0",
"opentelemetry-instrumentation-asgi >=0.49b0,<1.0",
- "reflex-base >= 0.9.11",
+ "reflex-base >= 0.10.0a2",
]
[project.entry-points.opentelemetry_instrumentor]
From 2742de4e82dcc009ca50a6c14c840c57ae0894f1 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 06:05:13 +0000
Subject: [PATCH 17/25] Materialize changelogs for hatch-reflex-pyi@0.10.0a1,
reflex-otel@0.2.0a1 (new-prerelease-minor)
---
packages/hatch-reflex-pyi/CHANGELOG.md | 5 +++++
.../hatch-reflex-pyi/news/+drop-python-310.breaking.md | 1 -
packages/reflex-otel/CHANGELOG.md | 8 ++++++++
packages/reflex-otel/news/+drop-python-310.breaking.md | 1 -
packages/reflex-otel/news/+reflex-base-0-10.breaking.md | 1 -
5 files changed, 13 insertions(+), 3 deletions(-)
create mode 100644 packages/hatch-reflex-pyi/CHANGELOG.md
delete mode 100644 packages/hatch-reflex-pyi/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-otel/news/+drop-python-310.breaking.md
delete mode 100644 packages/reflex-otel/news/+reflex-base-0-10.breaking.md
diff --git a/packages/hatch-reflex-pyi/CHANGELOG.md b/packages/hatch-reflex-pyi/CHANGELOG.md
new file mode 100644
index 00000000000..966ed24970a
--- /dev/null
+++ b/packages/hatch-reflex-pyi/CHANGELOG.md
@@ -0,0 +1,5 @@
+## v0.10.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
diff --git a/packages/hatch-reflex-pyi/news/+drop-python-310.breaking.md b/packages/hatch-reflex-pyi/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/hatch-reflex-pyi/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-otel/CHANGELOG.md b/packages/reflex-otel/CHANGELOG.md
index 881cf8cc3ab..fc2ca10b0eb 100644
--- a/packages/reflex-otel/CHANGELOG.md
+++ b/packages/reflex-otel/CHANGELOG.md
@@ -2,6 +2,14 @@
+## v0.2.0a1 (2026-10-06)
+
+### Breaking Changes
+
+- Require Python 3.11 or newer; Python 3.10 is no longer supported.
+- Require `reflex-base` 0.10 or newer.
+
+
## v0.1.0 (2026-09-11)
### Features
diff --git a/packages/reflex-otel/news/+drop-python-310.breaking.md b/packages/reflex-otel/news/+drop-python-310.breaking.md
deleted file mode 100644
index 4d55e54b6e6..00000000000
--- a/packages/reflex-otel/news/+drop-python-310.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require Python 3.11 or newer; Python 3.10 is no longer supported.
diff --git a/packages/reflex-otel/news/+reflex-base-0-10.breaking.md b/packages/reflex-otel/news/+reflex-base-0-10.breaking.md
deleted file mode 100644
index 15faae1789e..00000000000
--- a/packages/reflex-otel/news/+reflex-base-0-10.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Require `reflex-base` 0.10 or newer.
From 555b667c12c9bee03d650dbc72232e91868389af Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 19:20:29 +0000
Subject: [PATCH 18/25] Materialize changelogs for reflex@0.10.0a3,
reflex-base@0.10.0a3 (continued-prerelease)
---
CHANGELOG.md | 22 +++++++++++++++++++
news/+component-cli-shim.bugfix.md | 1 -
news/+db-extra-greenlet.bugfix.md | 1 -
...hydrate-get-delta-client-storage.bugfix.md | 1 -
news/+state-default-patch-restore.bugfix.md | 1 -
news/+state-store-mixed-versions.breaking.md | 1 -
news/+storage-default-assignment.bugfix.md | 1 -
news/+undeclared-private-name-guard.bugfix.md | 1 -
news/+upgrading-to-0-10.docs.md | 1 -
news/7312.breaking.md | 1 -
news/7462.breaking.md | 1 -
packages/reflex-base/CHANGELOG.md | 13 +++++++++++
.../news/+backend-var-format-hint.misc.md | 1 -
.../news/+json-output-slow-consumer.bugfix.md | 1 -
.../+state-default-patch-restore.bugfix.md | 1 -
.../+storage-default-assignment.bugfix.md | 1 -
16 files changed, 35 insertions(+), 14 deletions(-)
delete mode 100644 news/+component-cli-shim.bugfix.md
delete mode 100644 news/+db-extra-greenlet.bugfix.md
delete mode 100644 news/+hydrate-get-delta-client-storage.bugfix.md
delete mode 100644 news/+state-default-patch-restore.bugfix.md
delete mode 100644 news/+state-store-mixed-versions.breaking.md
delete mode 100644 news/+storage-default-assignment.bugfix.md
delete mode 100644 news/+undeclared-private-name-guard.bugfix.md
delete mode 100644 news/+upgrading-to-0-10.docs.md
delete mode 100644 news/7312.breaking.md
delete mode 100644 news/7462.breaking.md
delete mode 100644 packages/reflex-base/news/+backend-var-format-hint.misc.md
delete mode 100644 packages/reflex-base/news/+json-output-slow-consumer.bugfix.md
delete mode 100644 packages/reflex-base/news/+state-default-patch-restore.bugfix.md
delete mode 100644 packages/reflex-base/news/+storage-default-assignment.bugfix.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f52d35aee23..118fd0fed27 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,25 @@
+## v0.10.0a3 (2026-10-07)
+
+### Breaking Changes
+
+- Calling a handler that a substate inherits from a parent state, as a method of `self` in a background task, now goes through the task's state proxy like any other handler. Outside `async with self`, a call that modifies state raises `ImmutableStateError` (0.9 ran it on the parent state without the lock), and inside it `type(self)` is `StateProxy`, so use `self.__class__` to get the state class. See [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/#calling-inherited-handlers-from-background-tasks). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
+- Remove the `sqlmodel<0.0.45` cap that 0.10.0a1 added to `reflex[db]`. From SQLModel 0.0.45 a plain `datetime` field is stored as UTC, so writes and filters need timezone-aware values and reads return aware ones. A fresh install, or `uv pip install -U` from 0.10.0a1 (which moves SQLModel 0.0.44 to the latest release), then breaks apps that use naive datetimes: declare the field with `sa_type=DateTime(timezone=False)` or pin `sqlmodel<0.0.45` to keep them, as described in [Datetimes and SQLModel upgrades](https://reflex.dev/docs/database/tables/#datetimes-and-sqlmodel-upgrades). ([#7462](https://github.com/reflex-dev/reflex/issues/7462))
+- Instances of Reflex 0.9 and 0.10 can no longer share a Redis or disk state store. A 0.10 instance loads state saved by 0.9, but a 0.9 instance discards state saved by 0.10, so a rolling deploy that runs both versions, or a rollback to 0.9 against the same store, resets the sessions that reach the older instance. Upgrade every instance of an app together, and clear the store (or start a fresh one) when rolling back. ([#7494](https://github.com/reflex-dev/reflex/issues/7494))
+
+### Bug Fixes
+
+- The `db` extra now installs `greenlet`, which SQLAlchemy 2.1 no longer pulls in on its own, so `rx.Model`, `rx.session()` and the `reflex db` commands work again on a fresh `pip install reflex[db]` instead of failing with `ImportError: The SQLAlchemy asyncio module requires that the Python 'greenlet' library is installed`. ([#7466](https://github.com/reflex-dev/reflex/issues/7466))
+- Pass the client-storage values a page loads with through `get_delta` overrides again, in a delta that can update browser storage, as before 0.10. This restores reflex-enterprise OIDC's cross-tab token check, so a tab that is reloaded or navigated back to after logging out in another tab is signed out. ([#7493](https://github.com/reflex-dev/reflex/issues/7493))
+- Assigning a plain default to a browser storage var through its state class, such as `cls.theme = initial` in `ComponentState.get_component` for `theme: str = rx.LocalStorage("light", name="theme")` or a `default_factory` producing one, keeps the var in browser storage with its name and options instead of silently turning it into an ordinary var or raising `TypeError`. ([#7495](https://github.com/reflex-dev/reflex/issues/7495))
+- Undoing a patch of a state var's default, such as with pytest's `monkeypatch.setattr` or `unittest.mock.patch.object` on a state class, restores the previous default instead of raising `TypeError` at teardown and leaking the patched default into later tests. ([#7495](https://github.com/reflex-dev/reflex/issues/7495))
+- In development mode, assigning an undeclared state attribute whose name only looks name-mangled, such as `self._typo__name = 1`, raises `SetUndefinedStateVarError` again. Names starting with a double underscore and private names mangled by the state's own class, its bases or its mixins remain plain attributes. ([#7495](https://github.com/reflex-dev/reflex/issues/7495))
+- `reflex component` and its old subcommands now exit with a pointer to the wrapping React docs and the [component template](https://github.com/reflex-dev/component-template) instead of "No such command". ([#7497](https://github.com/reflex-dev/reflex/issues/7497))
+
+### Documentation
+
+- Add an [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/) guide. It covers reading a backend var's default on a state class (`State._x.default_value()` is new in 0.10; on 0.9 use `State.get_fields()["_x"].default_value()`), the scope of class-level default assignment, and inherited handlers called from background tasks. ([#7496](https://github.com/reflex-dev/reflex/issues/7496))
+
+
## v0.10.0a2 (2026-10-06)
### Breaking Changes
diff --git a/news/+component-cli-shim.bugfix.md b/news/+component-cli-shim.bugfix.md
deleted file mode 100644
index 4437fe74ccf..00000000000
--- a/news/+component-cli-shim.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`reflex component` and its old subcommands now exit with a pointer to the wrapping React docs and the [component template](https://github.com/reflex-dev/component-template) instead of "No such command".
diff --git a/news/+db-extra-greenlet.bugfix.md b/news/+db-extra-greenlet.bugfix.md
deleted file mode 100644
index a921c7298b6..00000000000
--- a/news/+db-extra-greenlet.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-The `db` extra now installs `greenlet`, which SQLAlchemy 2.1 no longer pulls in on its own, so `rx.Model`, `rx.session()` and the `reflex db` commands work again on a fresh `pip install reflex[db]` instead of failing with `ImportError: The SQLAlchemy asyncio module requires that the Python 'greenlet' library is installed`.
diff --git a/news/+hydrate-get-delta-client-storage.bugfix.md b/news/+hydrate-get-delta-client-storage.bugfix.md
deleted file mode 100644
index c947c746561..00000000000
--- a/news/+hydrate-get-delta-client-storage.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Pass the client-storage values a page loads with through `get_delta` overrides again, in a delta that can update browser storage, as before 0.10. This restores reflex-enterprise OIDC's cross-tab token check, so a tab that is reloaded or navigated back to after logging out in another tab is signed out.
diff --git a/news/+state-default-patch-restore.bugfix.md b/news/+state-default-patch-restore.bugfix.md
deleted file mode 100644
index 858db8cddff..00000000000
--- a/news/+state-default-patch-restore.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Undoing a patch of a state var's default, such as with pytest's `monkeypatch.setattr` or `unittest.mock.patch.object` on a state class, restores the previous default instead of raising `TypeError` at teardown and leaking the patched default into later tests.
diff --git a/news/+state-store-mixed-versions.breaking.md b/news/+state-store-mixed-versions.breaking.md
deleted file mode 100644
index fde71e948a2..00000000000
--- a/news/+state-store-mixed-versions.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Instances of Reflex 0.9 and 0.10 can no longer share a Redis or disk state store. A 0.10 instance loads state saved by 0.9, but a 0.9 instance discards state saved by 0.10, so a rolling deploy that runs both versions, or a rollback to 0.9 against the same store, resets the sessions that reach the older instance. Upgrade every instance of an app together, and clear the store (or start a fresh one) when rolling back.
diff --git a/news/+storage-default-assignment.bugfix.md b/news/+storage-default-assignment.bugfix.md
deleted file mode 100644
index cefc5c09e40..00000000000
--- a/news/+storage-default-assignment.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Assigning a plain default to a browser storage var through its state class, such as `cls.theme = initial` in `ComponentState.get_component` for `theme: str = rx.LocalStorage("light", name="theme")` or a `default_factory` producing one, keeps the var in browser storage with its name and options instead of silently turning it into an ordinary var or raising `TypeError`.
diff --git a/news/+undeclared-private-name-guard.bugfix.md b/news/+undeclared-private-name-guard.bugfix.md
deleted file mode 100644
index bad6fcdb387..00000000000
--- a/news/+undeclared-private-name-guard.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-In development mode, assigning an undeclared state attribute whose name only looks name-mangled, such as `self._typo__name = 1`, raises `SetUndefinedStateVarError` again. Names starting with a double underscore and private names mangled by the state's own class, its bases or its mixins remain plain attributes.
diff --git a/news/+upgrading-to-0-10.docs.md b/news/+upgrading-to-0-10.docs.md
deleted file mode 100644
index df208c03129..00000000000
--- a/news/+upgrading-to-0-10.docs.md
+++ /dev/null
@@ -1 +0,0 @@
-Add an [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/) guide. It covers reading a backend var's default on a state class (`State._x.default_value()` is new in 0.10; on 0.9 use `State.get_fields()["_x"].default_value()`), the scope of class-level default assignment, and inherited handlers called from background tasks.
diff --git a/news/7312.breaking.md b/news/7312.breaking.md
deleted file mode 100644
index 76b0fec228d..00000000000
--- a/news/7312.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Calling a handler that a substate inherits from a parent state, as a method of `self` in a background task, now goes through the task's state proxy like any other handler. Outside `async with self`, a call that modifies state raises `ImmutableStateError` (0.9 ran it on the parent state without the lock), and inside it `type(self)` is `StateProxy`, so use `self.__class__` to get the state class. See [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/#calling-inherited-handlers-from-background-tasks).
diff --git a/news/7462.breaking.md b/news/7462.breaking.md
deleted file mode 100644
index d1596c92ab4..00000000000
--- a/news/7462.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Remove the `sqlmodel<0.0.45` cap that 0.10.0a1 added to `reflex[db]`. From SQLModel 0.0.45 a plain `datetime` field is stored as UTC, so writes and filters need timezone-aware values and reads return aware ones. A fresh install, or `uv pip install -U` from 0.10.0a1 (which moves SQLModel 0.0.44 to the latest release), then breaks apps that use naive datetimes: declare the field with `sa_type=DateTime(timezone=False)` or pin `sqlmodel<0.0.45` to keep them, as described in [Datetimes and SQLModel upgrades](https://reflex.dev/docs/database/tables/#datetimes-and-sqlmodel-upgrades).
diff --git a/packages/reflex-base/CHANGELOG.md b/packages/reflex-base/CHANGELOG.md
index 663b9f24504..4d4eceada2a 100644
--- a/packages/reflex-base/CHANGELOG.md
+++ b/packages/reflex-base/CHANGELOG.md
@@ -1,3 +1,16 @@
+## v0.10.0a3 (2026-10-07)
+
+### Bug Fixes
+
+- Avoid premature truncation of JSON logs when consumers read slowly during shutdown, while limiting output draining to 30 seconds after the command exits. ([#7428](https://github.com/reflex-dev/reflex/issues/7428))
+- A plain value assigned through a state class, or produced by an assigned factory, to a field whose default is a browser storage value, or whose default factory produces one, keeps that storage type and options. ([#7495](https://github.com/reflex-dev/reflex/issues/7495))
+- Assigning a field (or its Var, read through the class) back to its state class, or deleting the class attribute, undoes the most recent default assignment, so patch-and-restore tools round-trip a class-level default. ([#7495](https://github.com/reflex-dev/reflex/issues/7495))
+
+### Miscellaneous
+
+- The `BackendVarFormatError` raised when a backend var is formatted into a string now names the fix: read its default with `State._var.default_value()`, declare a constant shared by all sessions as `ClassVar[...]`, or use a regular state var for a value the UI shows and updates. ([#7496](https://github.com/reflex-dev/reflex/issues/7496))
+
+
## v0.10.0a2 (2026-10-06)
### Breaking Changes
diff --git a/packages/reflex-base/news/+backend-var-format-hint.misc.md b/packages/reflex-base/news/+backend-var-format-hint.misc.md
deleted file mode 100644
index 2307185ba2f..00000000000
--- a/packages/reflex-base/news/+backend-var-format-hint.misc.md
+++ /dev/null
@@ -1 +0,0 @@
-The `BackendVarFormatError` raised when a backend var is formatted into a string now names the fix: read its default with `State._var.default_value()`, declare a constant shared by all sessions as `ClassVar[...]`, or use a regular state var for a value the UI shows and updates.
diff --git a/packages/reflex-base/news/+json-output-slow-consumer.bugfix.md b/packages/reflex-base/news/+json-output-slow-consumer.bugfix.md
deleted file mode 100644
index a65cae0e572..00000000000
--- a/packages/reflex-base/news/+json-output-slow-consumer.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Avoid premature truncation of JSON logs when consumers read slowly during shutdown, while limiting output draining to 30 seconds after the command exits.
diff --git a/packages/reflex-base/news/+state-default-patch-restore.bugfix.md b/packages/reflex-base/news/+state-default-patch-restore.bugfix.md
deleted file mode 100644
index 1192a8e283f..00000000000
--- a/packages/reflex-base/news/+state-default-patch-restore.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Assigning a field (or its Var, read through the class) back to its state class, or deleting the class attribute, undoes the most recent default assignment, so patch-and-restore tools round-trip a class-level default.
diff --git a/packages/reflex-base/news/+storage-default-assignment.bugfix.md b/packages/reflex-base/news/+storage-default-assignment.bugfix.md
deleted file mode 100644
index de88aae41bb..00000000000
--- a/packages/reflex-base/news/+storage-default-assignment.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-A plain value assigned through a state class, or produced by an assigned factory, to a field whose default is a browser storage value, or whose default factory produces one, keeps that storage type and options.
From f6e070ef4d32ba509a3ab1e8d3bb4c2052ee348c Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 8 Oct 2026 14:52:08 +0000
Subject: [PATCH 19/25] Materialize changelogs for reflex@0.10.0a4,
reflex-base@0.10.0a4 (continued-prerelease)
---
CHANGELOG.md | 7 +++++++
news/+state-var-class-assignment.breaking.md | 1 -
packages/reflex-base/CHANGELOG.md | 11 +++++++++++
.../news/+state-var-class-assignment.breaking.md | 1 -
.../reflex-base/news/+synced-storage-echo.bugfix.md | 1 -
5 files changed, 18 insertions(+), 3 deletions(-)
delete mode 100644 news/+state-var-class-assignment.breaking.md
delete mode 100644 packages/reflex-base/news/+state-var-class-assignment.breaking.md
delete mode 100644 packages/reflex-base/news/+synced-storage-echo.bugfix.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 204d2b7215c..e68de072359 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a4 (2026-10-08)
+
+### Breaking Changes
+
+- Assigning a state var through its state class, such as `State.count = 10`, raises `TypeError` instead of replacing the var; so do pytest's `monkeypatch.setattr` and `unittest.mock.patch.object` on a var. Change a default with `State.__fields__["count"].default = 10`, patch the field in tests, and declare class-level configuration as `ClassVar`. ([#7516](https://github.com/reflex-dev/reflex/issues/7516))
+
+
## v0.10.0a3 (2026-10-07)
### Breaking Changes
diff --git a/news/+state-var-class-assignment.breaking.md b/news/+state-var-class-assignment.breaking.md
deleted file mode 100644
index 42639d91265..00000000000
--- a/news/+state-var-class-assignment.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Assigning a state var through its state class, such as `State.count = 10`, raises `TypeError` instead of replacing the var; so do pytest's `monkeypatch.setattr` and `unittest.mock.patch.object` on a var. Change a default with `State.__fields__["count"].default = 10`, patch the field in tests, and declare class-level configuration as `ClassVar`.
diff --git a/packages/reflex-base/CHANGELOG.md b/packages/reflex-base/CHANGELOG.md
index c1a1b2fc63e..de5bdd23dec 100644
--- a/packages/reflex-base/CHANGELOG.md
+++ b/packages/reflex-base/CHANGELOG.md
@@ -1,3 +1,14 @@
+## v0.10.0a4 (2026-10-08)
+
+### Breaking Changes
+
+- Assigning over a state var's field through its state class raises `TypeError`; change its default on the field in `__fields__` instead. ([#7516](https://github.com/reflex-dev/reflex/issues/7516))
+
+### Bug Fixes
+
+- `sync=True` `rx.LocalStorage` vars 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](https://github.com/reflex-dev/reflex/issues/7505))
+
+
## v0.10.0a3 (2026-10-07)
### Bug Fixes
diff --git a/packages/reflex-base/news/+state-var-class-assignment.breaking.md b/packages/reflex-base/news/+state-var-class-assignment.breaking.md
deleted file mode 100644
index b02ecd0a6fa..00000000000
--- a/packages/reflex-base/news/+state-var-class-assignment.breaking.md
+++ /dev/null
@@ -1 +0,0 @@
-Assigning over a state var's field through its state class raises `TypeError`; change its default on the field in `__fields__` instead.
diff --git a/packages/reflex-base/news/+synced-storage-echo.bugfix.md b/packages/reflex-base/news/+synced-storage-echo.bugfix.md
deleted file mode 100644
index 7bc41deeb94..00000000000
--- a/packages/reflex-base/news/+synced-storage-echo.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-`sync=True` `rx.LocalStorage` vars 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.
From 57aee8ccf0a7fbb704ccc4d517ad6be8cad4ba4f Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 8 Oct 2026 19:16:26 +0000
Subject: [PATCH 20/25] Materialize changelogs for reflex@0.10.0a5,
reflex-base@0.10.0a5 (continued-prerelease)
---
CHANGELOG.md | 11 +++++++++++
news/+router-cookie-privacy.bugfix.md | 1 -
news/+router-cookie-privacy.deprecation.md | 1 -
packages/reflex-base/CHANGELOG.md | 7 +++++++
.../reflex-base/news/+field-set-default.feature.md | 1 -
5 files changed, 18 insertions(+), 3 deletions(-)
delete mode 100644 news/+router-cookie-privacy.bugfix.md
delete mode 100644 news/+router-cookie-privacy.deprecation.md
delete mode 100644 packages/reflex-base/news/+field-set-default.feature.md
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 299d6dbeb3a..63383f1f340 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## v0.10.0a5 (2026-10-08)
+
+### Deprecations
+
+- Deprecate `State.router.headers.cookie` and `State.router.headers["cookie"]` in components; both now render an empty string. Use `rx.Cookie` for cookies that need to be accessible to the frontend. ([#7360](https://github.com/reflex-dev/reflex/issues/7360))
+
+### Bug Fixes
+
+- Stop sending request cookies, including HttpOnly cookies, and standard authorization, Cloudflare Access, OAuth2 Proxy, AWS ALB, and Google IAP credential headers to frontend router data. On-load events no longer copy request router metadata to the frontend; server-side access to request headers is unchanged. ([#7360](https://github.com/reflex-dev/reflex/issues/7360))
+
+
## v0.10.0a4 (2026-10-08)
### Breaking Changes
diff --git a/news/+router-cookie-privacy.bugfix.md b/news/+router-cookie-privacy.bugfix.md
deleted file mode 100644
index 2961c092e41..00000000000
--- a/news/+router-cookie-privacy.bugfix.md
+++ /dev/null
@@ -1 +0,0 @@
-Stop sending request cookies, including HttpOnly cookies, and standard authorization, Cloudflare Access, OAuth2 Proxy, AWS ALB, and Google IAP credential headers to frontend router data. On-load events no longer copy request router metadata to the frontend; server-side access to request headers is unchanged.
diff --git a/news/+router-cookie-privacy.deprecation.md b/news/+router-cookie-privacy.deprecation.md
deleted file mode 100644
index 2cfc9f9768f..00000000000
--- a/news/+router-cookie-privacy.deprecation.md
+++ /dev/null
@@ -1 +0,0 @@
-Deprecate `State.router.headers.cookie` and `State.router.headers["cookie"]` in components; both now render an empty string. Use `rx.Cookie` for cookies that need to be accessible to the frontend.
diff --git a/packages/reflex-base/CHANGELOG.md b/packages/reflex-base/CHANGELOG.md
index 64d932bb6de..1c74e1e2a69 100644
--- a/packages/reflex-base/CHANGELOG.md
+++ b/packages/reflex-base/CHANGELOG.md
@@ -1,3 +1,10 @@
+## v0.10.0a5 (2026-10-08)
+
+### Features
+
+- Add `Field.set_default` to change a state var's default, given exactly one of `default` or `default_factory`, such as `State.__fields__["items"].set_default(["a"])`. A mutable `default` is copied when set and again for each instance, so sessions never share it. The `TypeError` for assigning a state var through its class now points at `set_default` on the field of the state that declares the var. ([#7519](https://github.com/reflex-dev/reflex/issues/7519))
+
+
## v0.10.0a4 (2026-10-08)
### Breaking Changes
diff --git a/packages/reflex-base/news/+field-set-default.feature.md b/packages/reflex-base/news/+field-set-default.feature.md
deleted file mode 100644
index fdd688dd70e..00000000000
--- a/packages/reflex-base/news/+field-set-default.feature.md
+++ /dev/null
@@ -1 +0,0 @@
-Add `Field.set_default` to change a state var's default, given exactly one of `default` or `default_factory`, such as `State.__fields__["items"].set_default(["a"])`. A mutable `default` is copied when set and again for each instance, so sessions never share it. The `TypeError` for assigning a state var through its class now points at `set_default` on the field of the state that declares the var.
From dac32ffccb638955567b8568ce07b2ae0483291a Mon Sep 17 00:00:00 2001
From: Claude
Date: Thu, 8 Oct 2026 20:01:47 +0000
Subject: [PATCH 21/25] Consolidate 0.10 pre-release changelogs into final
release notes
Collapse each package's pre-release sections under its newest pre-release
heading, group the larger categories under subheadings, and drop entries
that only fixed regressions introduced and resolved within the 0.10
pre-releases (boot hydration storage, cross-tab storage echoes, mangled-name
guard, supervised output draining) or that are superseded or internal
(reflex-base 0.9.12 floors, sibling version floors, BUN_OPTIONS, routes.json
constant, unreleased reflex-workflow logging). Merge related entries
(reflex component CLI removal, BackendVarFormatError, buffered uploads) and
split the reflex-hosting-cli output changes into a list.
Co-Authored-By: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_0163uzvnGNDwtVmqGKqwSmWC
---
CHANGELOG.md | 109 +++++++-----------
packages/reflex-base/CHANGELOG.md | 92 ++++++---------
packages/reflex-components-code/CHANGELOG.md | 3 -
packages/reflex-components-core/CHANGELOG.md | 4 -
.../reflex-components-gridjs/CHANGELOG.md | 7 --
.../reflex-components-markdown/CHANGELOG.md | 7 --
.../reflex-components-moment/CHANGELOG.md | 3 -
.../reflex-components-plotly/CHANGELOG.md | 3 -
packages/reflex-components-radix/CHANGELOG.md | 7 --
.../reflex-components-recharts/CHANGELOG.md | 4 -
packages/reflex-docgen/CHANGELOG.md | 3 -
packages/reflex-hosting-cli/CHANGELOG.md | 11 +-
12 files changed, 85 insertions(+), 168 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 63383f1f340..af50d029314 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,112 +1,89 @@
## v0.10.0a5 (2026-10-08)
-### Deprecations
-
-- Deprecate `State.router.headers.cookie` and `State.router.headers["cookie"]` in components; both now render an empty string. Use `rx.Cookie` for cookies that need to be accessible to the frontend. ([#7360](https://github.com/reflex-dev/reflex/issues/7360))
-
-### Bug Fixes
-
-- Stop sending request cookies, including HttpOnly cookies, and standard authorization, Cloudflare Access, OAuth2 Proxy, AWS ALB, and Google IAP credential headers to frontend router data. On-load events no longer copy request router metadata to the frontend; server-side access to request headers is unchanged. ([#7360](https://github.com/reflex-dev/reflex/issues/7360))
-
-
-## v0.10.0a4 (2026-10-08)
-
### Breaking Changes
-- Assigning a state var through its state class, such as `State.count = 10`, raises `TypeError` instead of replacing the var; so do pytest's `monkeypatch.setattr` and `unittest.mock.patch.object` on a var. Change a default with `State.__fields__["count"].set_default(10)`, patch the field in tests, and declare class-level configuration as `ClassVar`. ([#7516](https://github.com/reflex-dev/reflex/issues/7516))
+#### Python and dependencies
+- Drop support for Python 3.10, which reaches end of life in October 2026. Reflex now requires Python 3.11 or newer. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+- `reflex[db]` allows SQLModel 0.0.45 and later, which stores a plain `datetime` field as UTC: writes and filters need timezone-aware values and reads return aware ones. To keep naive datetimes, declare the field with `sa_type=DateTime(timezone=False)` or pin `sqlmodel<0.0.45`, as described in [Datetimes and SQLModel upgrades](https://reflex.dev/docs/database/tables/#datetimes-and-sqlmodel-upgrades). ([#7462](https://github.com/reflex-dev/reflex/issues/7462))
-## v0.10.0a3 (2026-10-07)
-
-### Breaking Changes
+#### State
+- Reading a backend var on a state class (`State._items`) now returns its `Field` descriptor instead of the var's default value. Passing it to a component, which used to bake the default into the frontend, now raises `ChildrenTypeError` as a child or `TypeError: Unsupported type for LiteralVar.` as a prop. To keep baking in the default, pass `State._items.default_value()` instead; to make the value reactive, declare a frontend var or computed var and pass that. See [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/#reading-a-backend-var-on-a-state-class). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
+- Assigning a state var through its state class, such as `State.count = 10`, raises `TypeError` instead of replacing the var; so do pytest's `monkeypatch.setattr` and `unittest.mock.patch.object` on a var. Change a default with `State.__fields__["count"].set_default(10)`, patch the field in tests, and declare class-level configuration as `ClassVar`. See [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/#assigning-a-state-var-through-its-class). ([#7516](https://github.com/reflex-dev/reflex/issues/7516))
- In a background task, calling a state-modifying handler inherited from a parent state, or writing an inherited var, outside `async with self` now raises `ImmutableStateError` like any other state change. See [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/#calling-inherited-handlers-from-background-tasks). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
-- Remove the `sqlmodel<0.0.45` cap that 0.10.0a1 added to `reflex[db]`. From SQLModel 0.0.45 a plain `datetime` field is stored as UTC, so writes and filters need timezone-aware values and reads return aware ones. A fresh install, or `uv pip install -U` from 0.10.0a1 (which moves SQLModel 0.0.44 to the latest release), then breaks apps that use naive datetimes: declare the field with `sa_type=DateTime(timezone=False)` or pin `sqlmodel<0.0.45` to keep them, as described in [Datetimes and SQLModel upgrades](https://reflex.dev/docs/database/tables/#datetimes-and-sqlmodel-upgrades). ([#7462](https://github.com/reflex-dev/reflex/issues/7462))
+- Assigning an undeclared state attribute still raises `SetUndefinedStateVarError` outside of prod mode, but no longer in prod. The internal class maps `backend_vars`, `inherited_vars` and `inherited_backend_vars`, `get_skip_vars()` and the instance `_backend_vars` are removed: use `get_fields()`, whose fields know the state they belong to. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
- Instances of Reflex 0.9 and 0.10 can no longer share a Redis or disk state store. A 0.10 instance loads state saved by 0.9, but a 0.9 instance discards state saved by 0.10, so a rolling deploy that runs both versions, or a rollback to 0.9 against the same store, resets the sessions that reach the older instance. Upgrade every instance of an app together, and clear the store (or start a fresh one) when rolling back. ([#7494](https://github.com/reflex-dev/reflex/issues/7494))
-### Bug Fixes
+#### CLI
-- The `db` extra now installs `greenlet`, which SQLAlchemy 2.1 no longer pulls in on its own, so `rx.Model`, `rx.session()` and the `reflex db` commands work again on a fresh `pip install reflex[db]` instead of failing with `ImportError: The SQLAlchemy asyncio module requires that the Python 'greenlet' library is installed`. ([#7466](https://github.com/reflex-dev/reflex/issues/7466))
-- Pass the client-storage values a page loads with through `get_delta` overrides again, in a delta that can update browser storage, as before 0.10. This restores reflex-enterprise OIDC's cross-tab token check, so a tab that is reloaded or navigated back to after logging out in another tab is signed out. ([#7493](https://github.com/reflex-dev/reflex/issues/7493))
-- In development mode, assigning an undeclared state attribute whose name only looks name-mangled, such as `self._typo__name = 1`, raises `SetUndefinedStateVarError` again. Names starting with a double underscore and private names mangled by the state's own class, its bases or its mixins remain plain attributes. ([#7495](https://github.com/reflex-dev/reflex/issues/7495))
-- `reflex component` and its old subcommands now exit with a pointer to the wrapping React docs and the [component template](https://github.com/reflex-dev/component-template) instead of "No such command". ([#7497](https://github.com/reflex-dev/reflex/issues/7497))
-
-### Documentation
-
-- Add an [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/) guide. It covers reading a backend var's default on a state class (`State._x.default_value()` is new in 0.10; on 0.9 use `State.get_fields()["_x"].default_value()`), the scope of class-level default assignment, and inherited handlers called from background tasks. ([#7496](https://github.com/reflex-dev/reflex/issues/7496))
+- Remove the `reflex component` CLI (`init`, `build`, `share`, `install`) and the `CustomComponents` constants; running `reflex component` now points to the replacements. Wrap React libraries directly in your app as described in the wrapping React docs, and start reusable component packages from the [component template](https://github.com/reflex-dev/component-template), which builds, tests, and publishes them with standard Python tooling. ([#6425](https://github.com/reflex-dev/reflex/issues/6425), [#7497](https://github.com/reflex-dev/reflex/issues/7497))
+### Deprecations
-## v0.10.0a2 (2026-10-06)
+- Deprecate `State.router.headers.cookie` and `State.router.headers["cookie"]` in components; both now render an empty string. Use `rx.Cookie` for cookies that need to be accessible to the frontend. ([#7360](https://github.com/reflex-dev/reflex/issues/7360))
-### Breaking Changes
+### Features
-- Drop support for Python 3.10, which reaches end of life in October 2026. Reflex now requires Python 3.11 or newer. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+- 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 `BaseVarShadowsInheritedVarError` or `ComputedVarShadowsBaseVarsError`. A dynamic route arg only conflicts with a var of the state it is installed on. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
+- The duration settings read by the app and the state managers take a unit suffix: `SQLALCHEMY_POOL_TIMEOUT`, `REFLEX_SOCKET_INTERVAL` and `REFLEX_SOCKET_TIMEOUT` accept values such as `2m`, and `REFLEX_AUTO_RELOAD_COOLDOWN`, `REFLEX_OPLOCK_HOLD_TIME` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE` replace the `_MS`/`_SECONDS` names, which still work with a deprecation warning until 1.0. A bare number is read as seconds. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
+- Set `REFLEX_REDIS_MAX_CONNECTIONS` to 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 to `REFLEX_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](https://github.com/reflex-dev/reflex/issues/7179))
### Bug Fixes
-- `AppHarness` now forgets the states of every module of the app's package when it stops, not only those of the app module, so a state defined elsewhere in the app (for example one using `rx.dynamic`) no longer breaks the next app started in the same test process. ([#7359](https://github.com/reflex-dev/reflex/issues/7359))
-- Deliver changes to client-storage and other state vars made by computed vars during hydration to the browser. ([#7460](https://github.com/reflex-dev/reflex/issues/7460))
-- Prevent hydration from persisting client-storage defaults. ([#7460](https://github.com/reflex-dev/reflex/issues/7460))
+#### State and events
+
+- Stop sending request cookies, including HttpOnly cookies, and standard authorization, Cloudflare Access, OAuth2 Proxy, AWS ALB, and Google IAP credential headers to frontend router data. On-load events no longer copy request router metadata to the frontend; server-side access to request headers is unchanged. ([#7360](https://github.com/reflex-dev/reflex/issues/7360))
- Defaults are no longer part of the saved-state schema, so changing one keeps state saved by this release or later loadable. A browser storage var annotated with a storage type, such as `rx.Field[rx.LocalStorage]`, and declared with a `default_factory` compiles with the storage options the factory produces, and `reset()` restores the factory's value. ([#7461](https://github.com/reflex-dev/reflex/issues/7461))
- Assigning a double-underscore private attribute on a state (`self.__counter = 1`) from a mixin, a base, or a class whose name starts with an underscore no longer raises `SetUndefinedStateVarError` in dev mode. Private names not explicitly declared with `rx.field()` are plain Python attributes: vars do not update in response to them. ([#7465](https://github.com/reflex-dev/reflex/issues/7465))
+- 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](https://github.com/reflex-dev/reflex/issues/7312))
+- A page URL with a `self` query parameter (e.g. `/post?self=1`), or a request header named `self`, no longer crashes router data parsing and leaves the page unhydrated. ([#7324](https://github.com/reflex-dev/reflex/issues/7324))
+- 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](https://github.com/reflex-dev/reflex/issues/7329))
+- 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](https://github.com/reflex-dev/reflex/issues/7318))
+- Fix a race with `REFLEX_OPLOCK_ENABLED` where 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](https://github.com/reflex-dev/reflex/issues/7372))
+- Fix `TypeError: refs._client_state_set... is not a function` when a component sets a global `rx._x.client_state` value before any component reading `.value` has mounted, such as when the reader sits behind an `rx.cond`. ([#7286](https://github.com/reflex-dev/reflex/issues/7286))
+- Preserve ID-based form controls through automatic memoization while excluding IDs on non-controls from submissions. ([#7227](https://github.com/reflex-dev/reflex/issues/7227))
-### Miscellaneous
-
-- Allow wrapt 2.4 and 2.5. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
-- Require sibling package versions from the Python 3.11 release train. ([#7464](https://github.com/reflex-dev/reflex/issues/7464))
-
-
-## v0.10.0a1 (2026-10-05)
-
-### Breaking Changes
-
-- Remove the `reflex component` CLI (`init`, `build`, `share`, `install`) and the `CustomComponents` constants. Wrap React libraries directly in your app as described in the wrapping React docs, and start reusable component packages from the [component template](https://github.com/reflex-dev/component-template), which builds, tests, and publishes them with standard Python tooling. ([#6425](https://github.com/reflex-dev/reflex/issues/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 `BaseVarShadowsInheritedVarError` or `ComputedVarShadowsBaseVarsError`. A dynamic route arg only conflicts with a var of the state it is installed on. Assigning an undeclared state attribute still raises `SetUndefinedStateVarError` outside of prod mode, but no longer in prod. The internal class maps `backend_vars`, `inherited_vars` and `inherited_backend_vars`, `get_skip_vars()` and the instance `_backend_vars` are removed: use `get_fields()`, whose fields know the state they belong to. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
-- Reading a backend var on a state class (`State._items`) now returns its `Field` descriptor instead of the var's default value. Passing it to a component, which used to bake the default into the frontend, now raises `ChildrenTypeError` as a child or `TypeError: Unsupported type for LiteralVar.` as a prop. To keep baking in the default, pass `State._items.default_value()` instead; to make the value reactive, declare a frontend var or computed var and pass that. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
-
-### Features
+#### Database
-- The duration settings read by the app and the state managers take a unit suffix: `SQLALCHEMY_POOL_TIMEOUT`, `REFLEX_SOCKET_INTERVAL` and `REFLEX_SOCKET_TIMEOUT` accept values such as `2m`, and `REFLEX_AUTO_RELOAD_COOLDOWN`, `REFLEX_OPLOCK_HOLD_TIME` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE` replace the `_MS`/`_SECONDS` names, which still work with a deprecation warning until 1.0. A bare number is read as seconds. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
-- Set `REFLEX_REDIS_MAX_CONNECTIONS` to 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 to `REFLEX_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](https://github.com/reflex-dev/reflex/issues/7179))
+- The `db` extra now installs `greenlet`, which SQLAlchemy 2.1 no longer pulls in on its own, so `rx.Model`, `rx.session()` and the `reflex db` commands work on a fresh `pip install reflex[db]` instead of failing with `ImportError: The SQLAlchemy asyncio module requires that the Python 'greenlet' library is installed`. ([#7466](https://github.com/reflex-dev/reflex/issues/7466))
+- Fixed `reflex db makemigrations`/`migrate` crashing with `CompileError` when autogenerating a migration that adds a column with a callable default (e.g. `default_factory=datetime.now` or `default=uuid.uuid4`) to an existing table; callable defaults are now evaluated before being carried as a SQL `server_default`. ([#6706](https://github.com/reflex-dev/reflex/issues/6706))
+- `reflex db` commands only require `sqlalchemy` and `alembic`, so apps that use plain SQLAlchemy models without `sqlmodel` can run migrations again. ([#7322](https://github.com/reflex-dev/reflex/issues/7322))
+- `reflex db` commands run without the `db` extra installed now exit with the "pip install reflex[db]" message instead of a raw traceback. ([#7259](https://github.com/reflex-dev/reflex/issues/7259))
-### Bug Fixes
+#### CLI, build and serving
-- Fixed `reflex db makemigrations`/`migrate` crashing with `CompileError` when autogenerating a migration that adds a column with a callable default (e.g. `default_factory=datetime.now` or `default=uuid.uuid4`) to an existing table; callable defaults are now evaluated before being carried as a SQL `server_default`. ([#6706](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/6996))
+- `reflex run` now 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](https://github.com/reflex-dev/reflex/issues/7328))
+- `reflex run --json` now emits every output line as a JSON record: `print()` output from the app, subprocess output, and worker tracebacks (as one record with an `exception` field) no longer break the JSON-lines stream. ([#7350](https://github.com/reflex-dev/reflex/issues/7350))
+- Fix stylesheet edits in `assets/` not applying in dev mode until a manual reload. ([#7317](https://github.com/reflex-dev/reflex/issues/7317))
+- Avoid reinstalling frontend packages on every compile or hot reload when bun or npm only changes the formatting of `package.json`. ([#7236](https://github.com/reflex-dev/reflex/issues/7236))
- When a project keeps using npm because `reflex.lock/` only has `package-lock.json` (for example after a run with `REFLEX_USE_NPM=1`), Reflex now logs why and how to switch back to bun with `REFLEX_USE_NPM=0`. ([#7093](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7210))
-- Preserve ID-based form controls through automatic memoization while excluding IDs on non-controls from submissions. ([#7227](https://github.com/reflex-dev/reflex/issues/7227))
-- Avoid reinstalling frontend packages on every compile or hot reload when bun or npm only changes the formatting of `package.json`. ([#7236](https://github.com/reflex-dev/reflex/issues/7236))
-- `reflex db` commands run without the `db` extra installed now exit with the "pip install reflex[db]" message instead of a raw traceback. ([#7259](https://github.com/reflex-dev/reflex/issues/7259))
-- Fix `TypeError: refs._client_state_set... is not a function` when a component sets a global `rx._x.client_state` value before any component reading `.value` has mounted, such as when the reader sits behind an `rx.cond`. ([#7286](https://github.com/reflex-dev/reflex/issues/7286))
- An editable install (`uv sync`, `pip install -e .`) no longer overwrites `.pyi` stubs that the checkout already has. A checkout missing any of them still gets them generated. ([#7303](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7312))
-- Fix stylesheet edits in `assets/` not applying in dev mode until a manual reload. The global stylesheet `` is now emitted only in production builds, so Vite's CSS hot update swaps the real stylesheet link again. ([#7317](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7318))
-- `reflex db` commands only require `sqlalchemy` and `alembic`, so apps that use plain SQLAlchemy models without `sqlmodel` can run migrations again. ([#7322](https://github.com/reflex-dev/reflex/issues/7322))
-- A page URL with a `self` query parameter (e.g. `/post?self=1`), or a request header named `self`, no longer crashes router data parsing and leaves the page unhydrated. ([#7324](https://github.com/reflex-dev/reflex/issues/7324))
-- `reflex run` now 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](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7348))
-- `reflex run --json` now emits every output line as a JSON record: `print()` output from the app, subprocess output, and worker tracebacks (as one record with an `exception` field) no longer break the JSON-lines stream. ([#7350](https://github.com/reflex-dev/reflex/issues/7350))
-- Fix a race with `REFLEX_OPLOCK_ENABLED` where 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](https://github.com/reflex-dev/reflex/issues/7372))
- Stop logging `asyncio.CancelledError: lifespan_cleanup` as an error when a running coroutine lifespan task is cancelled at backend shutdown or hot reload. ([#7392](https://github.com/reflex-dev/reflex/issues/7392))
+#### Testing
+
+- `AppHarness` now forgets the states of every module of the app's package when it stops, not only those of the app module, so a state defined elsewhere in the app (for example one using `rx.dynamic`) no longer breaks the next app started in the same test process. ([#7359](https://github.com/reflex-dev/reflex/issues/7359))
+
### 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](https://github.com/reflex-dev/reflex/issues/7064))
-- Reuse unchanged memo-body analysis during module emission to reduce repeated rendering and artifact collection. ([#7123](https://github.com/reflex-dev/reflex/issues/7123))
-- Skip the linked-client fan-out on events that changed nothing shared, so an app that defines an `rx.SharedState` no longer resolves the running `App` on every event. ([#7237](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7370))
+- Apps that define an `rx.SharedState` no longer pay extra per-event work for events that change no shared state. ([#7237](https://github.com/reflex-dev/reflex/issues/7237))
+- Compile memoized components faster by reusing unchanged memo bodies instead of rendering them again. ([#7123](https://github.com/reflex-dev/reflex/issues/7123))
### Documentation
+- Add an [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/) guide covering the changes most likely to break an existing app, with the fix for each. ([#7496](https://github.com/reflex-dev/reflex/issues/7496))
- Document the dict form for `rx.toast` `action` and `cancel` props instead of referencing the non-public `ToastAction` class. ([#7327](https://github.com/reflex-dev/reflex/issues/7327))
### Miscellaneous
-- No longer set `BUN_OPTIONS` when launching the frontend dev server; bun ignores it for the process it spawns for a package script. ([#7203](https://github.com/reflex-dev/reflex/issues/7203))
+- Allow wrapt 2.4 and 2.5. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
## v0.9.12 (2026-09-21)
diff --git a/packages/reflex-base/CHANGELOG.md b/packages/reflex-base/CHANGELOG.md
index 1c74e1e2a69..1d1c08d3ac3 100644
--- a/packages/reflex-base/CHANGELOG.md
+++ b/packages/reflex-base/CHANGELOG.md
@@ -1,93 +1,67 @@
## v0.10.0a5 (2026-10-08)
-### Features
-
-- Add `Field.set_default` to change a state var's default, given exactly one of `default` or `default_factory`, such as `State.__fields__["items"].set_default(["a"])`. A mutable `default` is copied when set and again for each instance, so sessions never share it. The `TypeError` for assigning a state var through its class now points at `set_default` on the field of the state that declares the var. ([#7519](https://github.com/reflex-dev/reflex/issues/7519))
-
-
-## v0.10.0a4 (2026-10-08)
-
-### Breaking Changes
-
-- Assigning over a state var's field through its state class raises `TypeError`; change its default with the field's `set_default` instead, such as `State.__fields__["count"].set_default(10)`. ([#7516](https://github.com/reflex-dev/reflex/issues/7516))
-
-### Bug Fixes
-
-- `sync=True` `rx.LocalStorage` vars 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](https://github.com/reflex-dev/reflex/issues/7505))
-
-
-## v0.10.0a3 (2026-10-07)
-
-### Bug Fixes
-
-- Avoid premature truncation of JSON logs when consumers read slowly during shutdown, while limiting output draining to 30 seconds after the command exits. ([#7428](https://github.com/reflex-dev/reflex/issues/7428))
-
-### Miscellaneous
-
-- The `BackendVarFormatError` raised when a backend var is formatted into a string now names the fix: read its default with `State._var.default_value()`, declare a constant shared by all sessions as `ClassVar[...]`, or use a regular state var for a value the UI shows and updates. ([#7496](https://github.com/reflex-dev/reflex/issues/7496))
-
-
-## v0.10.0a2 (2026-10-06)
-
### Breaking Changes
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
+- Assigning over a state var's field through its state class raises `TypeError`; change its default with the field's `set_default` instead, such as `State.__fields__["count"].set_default(10)`. ([#7516](https://github.com/reflex-dev/reflex/issues/7516))
+- Formatting a backend var as a string, e.g. `width=f"{State._size}px"`, now raises `BackendVarFormatError` (a `VarTypeError`) instead of embedding its default value. The error names the fix: read its default with `State._size.default_value()`, declare a constant shared by all sessions as `ClassVar[...]`, or use a regular state var for a value the UI shows and updates. ([#7456](https://github.com/reflex-dev/reflex/issues/7456), [#7496](https://github.com/reflex-dev/reflex/issues/7496))
+- `reflex_base.utils.types.is_backend_base_variable` and `RESERVED_BACKEND_VAR_NAMES` are removed: whether a state var is a backend var is now a property of its `Field` in `get_fields()`. By convention, fields named with a leading `_` are backend vars. `is_mutable_type` moved to `reflex_base.utils.types` (still importable from `reflex.istate.proxy`). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
+- `PageContext.get()` and `CompileContext.get()` now raise `LookupError` instead of `RuntimeError` when no context is active, the same as every other `BaseContext` subclass. Compiler plugins that catch `RuntimeError` around these calls should catch `LookupError`. ([#6553](https://github.com/reflex-dev/reflex/issues/6553))
+- Remove `reflex_base.constants.CustomComponents`, which only the removed `reflex component` CLI used. ([#6425](https://github.com/reflex-dev/reflex/issues/6425))
### Features
-- A double-underscore state attribute (a name-mangled `__private` name or a dunder) can now be a backend var by declaring it with an explicit `rx.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](https://github.com/reflex-dev/reflex/issues/7465))
-
-### Bug Fixes
-
-- Formatting a backend var as a string, e.g. `width=f"{State._size}px"`, now raises `BackendVarFormatError` (a `VarTypeError`) instead of silently embedding the field's repr in the page. ([#7456](https://github.com/reflex-dev/reflex/issues/7456))
-
-
-## v0.10.0a1 (2026-10-05)
-
-### Breaking Changes
+#### State vars
-- Remove `reflex_base.constants.CustomComponents`, which only the removed `reflex component` CLI used. ([#6425](https://github.com/reflex-dev/reflex/issues/6425))
-- `PageContext.get()` and `CompileContext.get()` now raise `LookupError` instead of `RuntimeError` when no context is active, the same as every other `BaseContext` subclass. Compiler plugins that catch `RuntimeError` around these calls should catch `LookupError`. ([#6553](https://github.com/reflex-dev/reflex/issues/6553))
-- `reflex_base.utils.types.is_backend_base_variable` and `RESERVED_BACKEND_VAR_NAMES` are removed: whether a state var is a backend var is now a property of its `Field` in `get_fields()`. By convention, fields named with a leading `_` are backend vars. `is_mutable_type` moved to `reflex_base.utils.types` (still importable from `reflex.istate.proxy`). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
+- `Field` is now the descriptor holding a state var's value, and `EventHandler` binds to the state that declares it when accessed on a state instance. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
+- Add `Field.set_default` to change a state var's default, given exactly one of `default` or `default_factory`, such as `State.__fields__["items"].set_default(["a"])`. A mutable `default` is copied when set and again for each instance, so sessions never share it. ([#7519](https://github.com/reflex-dev/reflex/issues/7519))
+- A double-underscore state attribute (a name-mangled `__private` name or a dunder) can now be a backend var by declaring it with an explicit `rx.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](https://github.com/reflex-dev/reflex/issues/7465))
-### Features
+#### Configuration
- `SQLALCHEMY_POOL_TIMEOUT`, `REFLEX_BACKEND_COLD_START_TIMEOUT`, `REFLEX_SOCKET_INTERVAL` and `REFLEX_SOCKET_TIMEOUT` are `timedelta` settings, so they accept a unit suffix such as `REFLEX_SOCKET_TIMEOUT=2m`. A bare number is still read as seconds, so existing values keep their meaning. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
- `REFLEX_AUTO_RELOAD_COOLDOWN`, `REFLEX_OPLOCK_HOLD_TIME` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE` replace `REFLEX_AUTO_RELOAD_COOLDOWN_TIME_MS`, `REFLEX_OPLOCK_HOLD_TIME_MS` and `REFLEX_STATE_MANAGER_DISK_DEBOUNCE_SECONDS`, and take a duration such as `250ms` or `5m`. The old names still work and keep counting the unit in their name, with a deprecation warning; they are removed in 1.0. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
- Add the `REFLEX_REDIS_MAX_CONNECTIONS` and `REFLEX_REDIS_POOL_TIMEOUT` environment 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](https://github.com/reflex-dev/reflex/issues/7179))
+
+#### Other
+
- Add `Var.deep_equals()` for structural comparison of nested frontend values. ([#7208](https://github.com/reflex-dev/reflex/issues/7208))
-- `Field` is now the descriptor holding a state var's value, and `EventHandler` binds to the state that declares it when accessed on a state instance. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
- 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](https://github.com/reflex-dev/reflex/issues/7350))
### Bug Fixes
+#### Vars and compilation
+
+- Negative-step slices of array and string Vars now match Python at a `-1` bound (e.g. `State.items[-1::-1]` no longer renders an empty list), and a Var step (e.g. `State.items[::State.step]`) no longer raises `RecursionError`. ([#7326](https://github.com/reflex-dev/reflex/issues/7326))
+- `Var._replace(_var_data=...)` no longer raises `TypeError: dataclasses.replace() got multiple values for keyword argument '_var_data'`. ([#7256](https://github.com/reflex-dev/reflex/issues/7256))
+- A state that mixes in `abc.ABC` or another `ABCMeta` class (`class MyMixin(ABC, rx.State, mixin=True)`) no longer fails with a `StateValueError` claiming `_abc_impl` is reserved by `BaseState`. ([#7339](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7414))
- Auto-memoized `@rx.memo` wrapper names no longer repeat the wrapped memo component's tag. ([#7004](https://github.com/reflex-dev/reflex/issues/7004))
-- Deprecation warnings no longer point at a pseudo-location such as `` or `` when the deprecated call runs inside generated or frozen code; the location now names the first real user file. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
+- 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](https://github.com/reflex-dev/reflex/issues/7369))
- Form submissions retain ID-backed controls with unset values while omitting IDs from non-controls. ([#7227](https://github.com/reflex-dev/reflex/issues/7227))
-- `Var._replace(_var_data=...)` no longer raises `TypeError: dataclasses.replace() got multiple values for keyword argument '_var_data'`. ([#7256](https://github.com/reflex-dev/reflex/issues/7256))
+
+#### Events and uploads
+
- Flatten nested client event lists before dispatch and keep processing queued events after one event fails. ([#7319](https://github.com/reflex-dev/reflex/issues/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_load` handlers 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](https://github.com/reflex-dev/reflex/issues/7357))
- `rx.download(data=State.var)` percent-encodes the JSON it puts in the `data:` URL, so a `#` or `%` in the data no longer truncates or corrupts the downloaded file. ([#7325](https://github.com/reflex-dev/reflex/issues/7325))
-- Negative-step slices of array and string Vars now match Python at a `-1` bound (e.g. `State.items[-1::-1]` no longer renders an empty list), and a Var step (e.g. `State.items[::State.step]`) no longer raises `RecursionError`. ([#7326](https://github.com/reflex-dev/reflex/issues/7326))
-- A state that mixes in `abc.ABC` or another `ABCMeta` class (`class MyMixin(ABC, rx.State, mixin=True)`) no longer fails with a `StateValueError` claiming `_abc_impl` is reserved by `BaseState`. ([#7339](https://github.com/reflex-dev/reflex/issues/7339))
-- Events sent while a buffered upload (or another `EventProcessor.enqueue_stream_delta` stream) 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_load` handlers again. Concurrent buffered uploads no longer hang or end each other's responses early. ([#7357](https://github.com/reflex-dev/reflex/issues/7357))
-- State changes made after a buffered 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](https://github.com/reflex-dev/reflex/issues/7357))
- 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 a `reflex.event.parent_txid` naming the event processor's root context; only chained events name the event that produced them. ([#7358](https://github.com/reflex-dev/reflex/issues/7358))
-- 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](https://github.com/reflex-dev/reflex/issues/7369))
-- 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](https://github.com/reflex-dev/reflex/issues/7414))
+
+#### Other
+
+- Deprecation warnings no longer point at a pseudo-location such as `` or `` when the deprecated call runs inside generated or frozen code; the location now names the first real user file. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
### Performance
-- Reduce event-queue overhead when prepending events and processing events with a connected socket. ([#7053](https://github.com/reflex-dev/reflex/issues/7053))
-- Begin opening the websocket transport before React mounts, then hydrate with a single `hydrate_and_load` event sent along with the websocket connect to save a round trip. ([#7064](https://github.com/reflex-dev/reflex/issues/7064))
-- Evaluate generated passthrough memo bodies once and retain their render and artifacts so module emission does not repeat the work. ([#7123](https://github.com/reflex-dev/reflex/issues/7123))
-- 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](https://github.com/reflex-dev/reflex/issues/7353))
-- 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](https://github.com/reflex-dev/reflex/issues/7370))
+- 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](https://github.com/reflex-dev/reflex/issues/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_background` and `EventHandler.supersedes` are read once per handler, so mark the function before the handler is first used. ([#7370](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/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](https://github.com/reflex-dev/reflex/issues/7353))
+- Reduce event-queue overhead when prepending events and processing events with a connected socket. ([#7053](https://github.com/reflex-dev/reflex/issues/7053))
+- Compile memoized components faster by reusing unchanged memo bodies instead of rendering them again. ([#7123](https://github.com/reflex-dev/reflex/issues/7123))
### Miscellaneous
-- Add the `routes.json` manifest name constant, written at compile time so the prod static file server can tell routable SPA paths from unknown ones. ([#6996](https://github.com/reflex-dev/reflex/issues/6996))
-- Route log records from the new `reflex-workflow` package through the Reflex logger, so they follow the configured log level and sinks. ([#7288](https://github.com/reflex-dev/reflex/issues/7288))
- 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](https://github.com/reflex-dev/reflex/issues/7424))
diff --git a/packages/reflex-components-code/CHANGELOG.md b/packages/reflex-components-code/CHANGELOG.md
index 06a6969727f..270c0639486 100644
--- a/packages/reflex-components-code/CHANGELOG.md
+++ b/packages/reflex-components-code/CHANGELOG.md
@@ -4,9 +4,6 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-
-## v0.10.0a1 (2026-10-05)
-
### Miscellaneous
- Update Shiki and its transformers to 4.5.0. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
diff --git a/packages/reflex-components-core/CHANGELOG.md b/packages/reflex-components-core/CHANGELOG.md
index 1220de24868..5eb721c83e8 100644
--- a/packages/reflex-components-core/CHANGELOG.md
+++ b/packages/reflex-components-core/CHANGELOG.md
@@ -4,9 +4,6 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-
-## v0.10.0a1 (2026-10-05)
-
### Features
- The connection banner reads `REFLEX_BACKEND_COLD_START_TIMEOUT` as a duration, so it accepts a unit suffix such as `30s`. A bare number is still read as seconds. ([#7138](https://github.com/reflex-dev/reflex/issues/7138))
@@ -15,7 +12,6 @@
- Fix `rx.match` raising `ReferenceError: Can't find variable` at render when a state Var is used only in a case condition with component branches. ([#6675](https://github.com/reflex-dev/reflex/issues/6675))
- Exclude IDs on forms and other non-controls from form submissions while preserving unset ID-backed controls and supporting custom controls marked with `_is_form_control`. ([#7227](https://github.com/reflex-dev/reflex/issues/7227))
-- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
### Miscellaneous
diff --git a/packages/reflex-components-gridjs/CHANGELOG.md b/packages/reflex-components-gridjs/CHANGELOG.md
index dcc7e6a2d8e..4e3dea9bc04 100644
--- a/packages/reflex-components-gridjs/CHANGELOG.md
+++ b/packages/reflex-components-gridjs/CHANGELOG.md
@@ -5,13 +5,6 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-## v0.10.0a1 (2026-10-05)
-
-### Bug Fixes
-
-- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
-
-
## v0.9.2.post1 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-markdown/CHANGELOG.md b/packages/reflex-components-markdown/CHANGELOG.md
index 62756042c7a..defbb045152 100644
--- a/packages/reflex-components-markdown/CHANGELOG.md
+++ b/packages/reflex-components-markdown/CHANGELOG.md
@@ -5,13 +5,6 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-## v0.10.0a1 (2026-10-05)
-
-### Bug Fixes
-
-- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
-
-
## v0.9.4.post1 (2026-09-21)
### Bug Fixes
diff --git a/packages/reflex-components-moment/CHANGELOG.md b/packages/reflex-components-moment/CHANGELOG.md
index fc4edc48ff0..7b0454741a8 100644
--- a/packages/reflex-components-moment/CHANGELOG.md
+++ b/packages/reflex-components-moment/CHANGELOG.md
@@ -4,9 +4,6 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-
-## v0.10.0a1 (2026-10-05)
-
### Miscellaneous
- Update Moment to 2.31.0, moment-timezone to 0.6.5, and moment-duration-format to 2.3.2. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
diff --git a/packages/reflex-components-plotly/CHANGELOG.md b/packages/reflex-components-plotly/CHANGELOG.md
index 9babbf4713a..443e0e4c380 100644
--- a/packages/reflex-components-plotly/CHANGELOG.md
+++ b/packages/reflex-components-plotly/CHANGELOG.md
@@ -4,9 +4,6 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-
-## v0.10.0a1 (2026-10-05)
-
### Bug Fixes
- Normalize string Plotly layout titles to the `{"title": {"text": "..."}}` format required by Plotly.js. ([#7226](https://github.com/reflex-dev/reflex/issues/7226))
diff --git a/packages/reflex-components-radix/CHANGELOG.md b/packages/reflex-components-radix/CHANGELOG.md
index eb70b44ecb2..8d81a1fe0bf 100644
--- a/packages/reflex-components-radix/CHANGELOG.md
+++ b/packages/reflex-components-radix/CHANGELOG.md
@@ -4,13 +4,6 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-
-## v0.10.0a1 (2026-10-05)
-
-### Bug Fixes
-
-- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
-
### Miscellaneous
- Update the Radix slider and progress dependencies to 1.4.7 and 1.1.16. ([#7424](https://github.com/reflex-dev/reflex/issues/7424))
diff --git a/packages/reflex-components-recharts/CHANGELOG.md b/packages/reflex-components-recharts/CHANGELOG.md
index 0bfa3a795b4..6ef98461929 100644
--- a/packages/reflex-components-recharts/CHANGELOG.md
+++ b/packages/reflex-components-recharts/CHANGELOG.md
@@ -4,12 +4,8 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-
-## v0.10.0a1 (2026-10-05)
-
### Bug Fixes
-- Require reflex-base 0.9.12 or newer so all imported rendering APIs are available. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
- Allow Recharts axis tick formatters to use Reflex function vars. ([#7366](https://github.com/reflex-dev/reflex/issues/7366))
diff --git a/packages/reflex-docgen/CHANGELOG.md b/packages/reflex-docgen/CHANGELOG.md
index f7f7f82c5a4..95b13d67883 100644
--- a/packages/reflex-docgen/CHANGELOG.md
+++ b/packages/reflex-docgen/CHANGELOG.md
@@ -4,9 +4,6 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
-
-## v0.10.0a1 (2026-10-05)
-
### Bug Fixes
- Recognize YAML frontmatter after a UTF-8 BOM or leading whitespace and with CRLF line endings, keeping metadata out of rendered page content and tables of contents. ([#7238](https://github.com/reflex-dev/reflex/issues/7238))
diff --git a/packages/reflex-hosting-cli/CHANGELOG.md b/packages/reflex-hosting-cli/CHANGELOG.md
index e00699f22b7..fee4bdeb1bb 100644
--- a/packages/reflex-hosting-cli/CHANGELOG.md
+++ b/packages/reflex-hosting-cli/CHANGELOG.md
@@ -2,7 +2,14 @@
### Breaking Changes
-- Some `reflex cloud` commands changed what they report. A refused request now exits non-zero rather than printing a `"... failed: ..."` line and exiting 0, and `--json` writes no document on that path; `apps stop`, `apps start` and `apps delete` are the ones most likely to be scripted against, and they now report their own outcome rather than echoing the server's sentence. `vmtypes` and `regions` answered a failed request with an empty listing and exit 0, which a script could not tell from a control plane that offers neither; they exit non-zero now. `apps history --json` replaces `hostname` with the deployment's `url`, reports `vm type` as the machine's name rather than an object, and reports `timestamp` as an ISO 8601 string with an offset; `apps inspect --json` drops `hostname` from `latest_deployment` the same way, the URL carrying it already. `create-token --json` replaces `expires_in_days` with `expires_at`, an ISO 8601 string or `null`, carrying the expiry the server applied rather than the duration that was asked for. `apps logs` drops its inert `--cursor` option and its `--json` document returns every line in the window rather than one page. `project role-permissions` lists permission names rather than objects. `reflex deploy` now requires a control plane that signs upload URLs; the multipart fallback for older ones is gone, and with it the "payload is too large (over 100MB)" hint, which only that path could produce. And `apps status --watch --json` reports `"success": null` when the watch stopped before the deployment ended -- it is still running, and the command did not see how it finished -- rather than answering `true` or `false` for something it does not know. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
+- Some `reflex cloud` commands changed what they report: ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
+ - A refused request exits non-zero instead of printing a `"... failed: ..."` line and exiting 0, and `--json` writes no document. This includes `vmtypes` and `regions`, which answered a failed request with an empty listing, and `apps stop`, `apps start` and `apps delete`, which now report their own outcome rather than echoing the server's message.
+ - `apps history --json` replaces `hostname` with the deployment's `url`, reports `vm type` as the machine's name rather than an object, and reports `timestamp` as an ISO 8601 string with an offset. `apps inspect --json` drops `hostname` from `latest_deployment`.
+ - `create-token --json` replaces `expires_in_days` with `expires_at`, an ISO 8601 string or `null`, carrying the expiry the server applied.
+ - `apps logs` drops its unused `--cursor` option, and its `--json` document returns every line in the window rather than one page.
+ - `apps status --watch --json` reports `"success": null` when the watch stopped before the deployment finished.
+ - `project role-permissions` lists permission names rather than objects.
+ - `reflex deploy` requires a control plane that signs upload URLs; the multipart upload fallback for older ones, and its "payload is too large (over 100MB)" hint, are gone.
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
### Bug Fixes
@@ -18,7 +25,7 @@
### Miscellaneous
-- `reflex-hosting-cli` now talks to Reflex Build through `reflex-build-sdk` rather than its own HTTP layer, so every command shares the SDK's retries, timeouts and typed errors. While the SDK is pre-1.0, where any release may change its API, the requirement is capped to the single patch line the CLI was built against, so upgrade `reflex-hosting-cli` to move to a newer SDK rather than upgrading the SDK on its own. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
+- `reflex-hosting-cli` now talks to Reflex Build through `reflex-build-sdk`, so every command shares the SDK's retries, timeouts and typed errors. While the SDK is pre-1.0, the CLI pins it to a single patch line, so upgrade `reflex-hosting-cli` to move to a newer SDK rather than upgrading the SDK on its own. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
## v0.1.72 (2026-09-11)
From 80d36782a589ef8808e5a0d73be558c707d42126 Mon Sep 17 00:00:00 2001
From: Claude
Date: Thu, 8 Oct 2026 20:19:53 +0000
Subject: [PATCH 22/25] Document deep-copied mutable state var defaults as a
breaking change
Co-Authored-By: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_0163uzvnGNDwtVmqGKqwSmWC
---
CHANGELOG.md | 1 +
packages/reflex-base/CHANGELOG.md | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index af50d029314..ba0cf3b9beb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
- Reading a backend var on a state class (`State._items`) now returns its `Field` descriptor instead of the var's default value. Passing it to a component, which used to bake the default into the frontend, now raises `ChildrenTypeError` as a child or `TypeError: Unsupported type for LiteralVar.` as a prop. To keep baking in the default, pass `State._items.default_value()` instead; to make the value reactive, declare a frontend var or computed var and pass that. See [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/#reading-a-backend-var-on-a-state-class). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
- Assigning a state var through its state class, such as `State.count = 10`, raises `TypeError` instead of replacing the var; so do pytest's `monkeypatch.setattr` and `unittest.mock.patch.object` on a var. Change a default with `State.__fields__["count"].set_default(10)`, patch the field in tests, and declare class-level configuration as `ClassVar`. See [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/#assigning-a-state-var-through-its-class). ([#7516](https://github.com/reflex-dev/reflex/issues/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 the `class` statement, such as `options: list[str] = OPTIONS` followed by `OPTIONS.append(...)`, now starts every session empty: fill it before the class is defined, or declare `default_factory=lambda: list(OPTIONS)`. ([#7519](https://github.com/reflex-dev/reflex/issues/7519))
- In a background task, calling a state-modifying handler inherited from a parent state, or writing an inherited var, outside `async with self` now raises `ImmutableStateError` like any other state change. See [Upgrading to Reflex 0.10](https://reflex.dev/docs/changelog/upgrading/upgrading-to-0-10/#calling-inherited-handlers-from-background-tasks). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
- Assigning an undeclared state attribute still raises `SetUndefinedStateVarError` outside of prod mode, but no longer in prod. The internal class maps `backend_vars`, `inherited_vars` and `inherited_backend_vars`, `get_skip_vars()` and the instance `_backend_vars` are removed: use `get_fields()`, whose fields know the state they belong to. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
- Instances of Reflex 0.9 and 0.10 can no longer share a Redis or disk state store. A 0.10 instance loads state saved by 0.9, but a 0.9 instance discards state saved by 0.10, so a rolling deploy that runs both versions, or a rollback to 0.9 against the same store, resets the sessions that reach the older instance. Upgrade every instance of an app together, and clear the store (or start a fresh one) when rolling back. ([#7494](https://github.com/reflex-dev/reflex/issues/7494))
diff --git a/packages/reflex-base/CHANGELOG.md b/packages/reflex-base/CHANGELOG.md
index 1d1c08d3ac3..79a1141c8c4 100644
--- a/packages/reflex-base/CHANGELOG.md
+++ b/packages/reflex-base/CHANGELOG.md
@@ -4,6 +4,7 @@
- Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
- Assigning over a state var's field through its state class raises `TypeError`; change its default with the field's `set_default` instead, such as `State.__fields__["count"].set_default(10)`. ([#7516](https://github.com/reflex-dev/reflex/issues/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 the `class` statement, such as `options: list[str] = OPTIONS` followed by `OPTIONS.append(...)`, now starts every session empty: fill it before the class is defined, or declare `default_factory=lambda: list(OPTIONS)`. ([#7519](https://github.com/reflex-dev/reflex/issues/7519))
- Formatting a backend var as a string, e.g. `width=f"{State._size}px"`, now raises `BackendVarFormatError` (a `VarTypeError`) instead of embedding its default value. The error names the fix: read its default with `State._size.default_value()`, declare a constant shared by all sessions as `ClassVar[...]`, or use a regular state var for a value the UI shows and updates. ([#7456](https://github.com/reflex-dev/reflex/issues/7456), [#7496](https://github.com/reflex-dev/reflex/issues/7496))
- `reflex_base.utils.types.is_backend_base_variable` and `RESERVED_BACKEND_VAR_NAMES` are removed: whether a state var is a backend var is now a property of its `Field` in `get_fields()`. By convention, fields named with a leading `_` are backend vars. `is_mutable_type` moved to `reflex_base.utils.types` (still importable from `reflex.istate.proxy`). ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
- `PageContext.get()` and `CompileContext.get()` now raise `LookupError` instead of `RuntimeError` when no context is active, the same as every other `BaseContext` subclass. Compiler plugins that catch `RuntimeError` around these calls should catch `LookupError`. ([#6553](https://github.com/reflex-dev/reflex/issues/6553))
@@ -14,7 +15,7 @@
#### State vars
- `Field` is now the descriptor holding a state var's value, and `EventHandler` binds to the state that declares it when accessed on a state instance. ([#7312](https://github.com/reflex-dev/reflex/issues/7312))
-- Add `Field.set_default` to change a state var's default, given exactly one of `default` or `default_factory`, such as `State.__fields__["items"].set_default(["a"])`. A mutable `default` is copied when set and again for each instance, so sessions never share it. ([#7519](https://github.com/reflex-dev/reflex/issues/7519))
+- Add `Field.set_default` to change a state var's default, given exactly one of `default` or `default_factory`, such as `State.__fields__["items"].set_default(["a"])`. ([#7519](https://github.com/reflex-dev/reflex/issues/7519))
- A double-underscore state attribute (a name-mangled `__private` name or a dunder) can now be a backend var by declaring it with an explicit `rx.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](https://github.com/reflex-dev/reflex/issues/7465))
#### Configuration
From f74469d543c9b398ef0c951ca91fc016f3e6cb73 Mon Sep 17 00:00:00 2001
From: Claude
Date: Thu, 8 Oct 2026 20:21:49 +0000
Subject: [PATCH 23/25] Document deep-copied mutable defaults in the 0.10
upgrade guide
Co-Authored-By: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_0163uzvnGNDwtVmqGKqwSmWC
---
docs/changelog/upgrading/upgrading-to-0-10.md | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/docs/changelog/upgrading/upgrading-to-0-10.md b/docs/changelog/upgrading/upgrading-to-0-10.md
index 00213e46009..d6f26a7f8d1 100644
--- a/docs/changelog/upgrading/upgrading-to-0-10.md
+++ b/docs/changelog/upgrading/upgrading-to-0-10.md
@@ -73,6 +73,28 @@ On 0.9, assigning `State.__fields__["items"].default = []` was safe, because eac
[Changing Defaults](/docs/vars/base-vars/#changing-defaults) has the details, including browser storage vars.
+## Mutable defaults filled in after the class is defined
+
+In 0.10 a mutable default given in the class body, or passed to `set_default`, is deep-copied when it is assigned ([#7519](https://github.com/reflex-dev/reflex/pull/7519)). Changes made to the original object afterwards no longer reach new sessions. On 0.9, a module-level list filled in after the `class` statement still showed up in every new session; on 0.10 sessions start with the list as it was when the class was defined:
+
+```python
+OPTIONS: list[str] = []
+
+
+class State(rx.State):
+ options: list[str] = OPTIONS
+
+
+OPTIONS.append("late") # 0.9: new sessions see ["late"]; 0.10: they see []
+```
+
+Fill the value before the class is defined, or declare a factory that reads it when each session starts, which works on both versions:
+
+```python
+class State(rx.State):
+ options: list[str] = rx.field(default_factory=lambda: list(OPTIONS))
+```
+
## Calling inherited handlers from background tasks
In a background task, `self` is a proxy that only allows changes inside `async with self`. A handler declared on the same state was already called through that proxy, but a handler inherited from a parent state was not: on 0.9, `self.inherited_handler()` ran on the parent state without the lock, so it could write outside `async with self`. In 0.10 it goes through the proxy like any other handler ([#7312](https://github.com/reflex-dev/reflex/pull/7312)):
From 012b0ebb20c0af3fb19315caec1d1e81dd1b9595 Mon Sep 17 00:00:00 2001
From: Claude
Date: Thu, 8 Oct 2026 20:31:00 +0000
Subject: [PATCH 24/25] Add the towncrier start marker to the hatch-reflex-pyi
changelog
Co-Authored-By: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_0163uzvnGNDwtVmqGKqwSmWC
---
packages/hatch-reflex-pyi/CHANGELOG.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/hatch-reflex-pyi/CHANGELOG.md b/packages/hatch-reflex-pyi/CHANGELOG.md
index 966ed24970a..e4745c6a56e 100644
--- a/packages/hatch-reflex-pyi/CHANGELOG.md
+++ b/packages/hatch-reflex-pyi/CHANGELOG.md
@@ -1,3 +1,5 @@
+
+
## v0.10.0a1 (2026-10-06)
### Breaking Changes
From f05eeb8dd6b85ee105f05061d747db1942172664 Mon Sep 17 00:00:00 2001
From: Claude
Date: Thu, 8 Oct 2026 20:42:08 +0000
Subject: [PATCH 25/25] Restore the sync=True LocalStorage cross-tab fix to the
reflex-base release notes
Co-Authored-By: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_0163uzvnGNDwtVmqGKqwSmWC
---
packages/reflex-base/CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/reflex-base/CHANGELOG.md b/packages/reflex-base/CHANGELOG.md
index 79a1141c8c4..2fd88967f9d 100644
--- a/packages/reflex-base/CHANGELOG.md
+++ b/packages/reflex-base/CHANGELOG.md
@@ -45,6 +45,7 @@
- Flatten nested client event lists before dispatch and keep processing queued events after one event fails. ([#7319](https://github.com/reflex-dev/reflex/issues/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_load` handlers 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](https://github.com/reflex-dev/reflex/issues/7357))
+- `sync=True` `rx.LocalStorage` vars 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](https://github.com/reflex-dev/reflex/issues/7505))
- `rx.download(data=State.var)` percent-encodes the JSON it puts in the `data:` URL, so a `#` or `%` in the data no longer truncates or corrupts the downloaded file. ([#7325](https://github.com/reflex-dev/reflex/issues/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 a `reflex.event.parent_txid` naming the event processor's root context; only chained events name the event that produced them. ([#7358](https://github.com/reflex-dev/reflex/issues/7358))