Reflex: full-stack web apps written entirely in Python
Web apps in pure Python. Introduction Reflex is a library to build full-stack web apps in pure Python.
At a glance
- What is it?
- Reflex compiles a Python class into frontend state and a backend event loop, so a single language covers the whole app. It is a good fit for Python teams that would otherwise have to hire for React, and a poor fit for anyone who needs a stable API surface today.
- Who is it for?
- Adopt Reflex if your team writes Python and the app is a stateful internal tool or dashboard where one language beats frontend flexibility. Do not adopt it if you need a frozen API surface, because pyproject.toml still carries the classifier Development Status :: 4 - Beta.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The Python-only gap Reflex is trying to close
A Python developer who needs a web interface normally ends up maintaining two codebases in two languages. The backend holds the data and the business rules; the frontend re-implements a slice of that logic in JavaScript, and every state shape has to be serialised across the boundary by hand. Reflex's pitch is that the boundary disappears. The README states the library is for building full-stack web apps in pure Python, and lists two key features: the frontend and backend are both written in Python, and the framework is meant to scale from a first prototype to a complex app.
The audience is narrow but real. Data scientists, internal tool builders, and backend engineers who already know Python and do not want to learn a component framework. It is not aimed at teams with an existing React codebase, and it is not aimed at static marketing sites, where a compiled Python state layer buys nothing.
How a State class becomes a running frontend and backend
The unit of the framework is the State class. In the README's image generation example, State declares typed attributes (prompt: str, image_url: str, processing: bool) and methods decorated with @rx.event. The class is the single source of truth: the browser does not hold its own copy of the logic, it holds a rendered view of that class.
Events are where the two halves meet. The example's generate method is async, sets processing = True, then calls yield before awaiting the image model. That bare yield is the mechanism that pushes the intermediate state to the client while the coroutine is still running, which is what lets a spinner appear during a slow API call. When the await returns, the method assigns image_url and processing = False, and the frontend updates again.
The README points to an architecture page for the details under the hood, and that page is not reproduced in the repository README, so the exact compilation pipeline is not something the README documents. What is visible is the shape: one Python class, decorated handlers, and a frontend that reflects it. The dependency list in pyproject.toml backs this up, pulling in starlette, python-socketio and granian, which is consistent with an HTTP server plus a persistent socket channel between browser and backend.
Installing Reflex with uv and running the dev server
The README recommends a virtual environment so that the reflex command lands on your PATH, and gives the uv workflow as the primary path. Create a directory, initialise a project, add the package, then run reflex init followed by reflex run.
mkdir my_app_name
cd my_app_name
uv init
uv add reflex
uv run reflex init
uv run reflex runAfter reflex run, the README says the app is reachable at http://localhost:3000. The reflex init step is separate from reflex run, and it is the step that scaffolds the project; skipping it means there is no app for the server to serve. Once the server is up, the source file to edit is my_app_name/my_app_name.py, and the README notes that saving changes triggers a fast refresh rather than a manual restart.
The install is a normal PyPI package. The package metadata sets requires-python to ">=3.10,<4.0", so Python 3.10 through 3.14 are the supported interpreters, and the classifiers list each of those versions explicitly. If your environment is on 3.9 or older, the install will not resolve.
The Beta classifier and the versioned component packages
The most concrete limitation is in the project metadata, not the prose. pyproject.toml carries the classifier Development Status :: 4 - Beta. That is the project's own label, and it should set expectations about API stability: a library in Beta can rename a decorator or change a state method signature between minor releases.
The second constraint is the dependency fan-out. Reflex is not one package. The dependency list includes reflex-base, reflex-hosting-cli, and a long row of component packages: reflex-components-radix, reflex-components-plotly, reflex-components-recharts, reflex-components-markdown, reflex-components-moment, reflex-components-lucide, reflex-components-gridjs, reflex-components-dataeditor, reflex-components-sonner, reflex-components-react-player, reflex-components-code and reflex-components-core, each with its own version floor. Upgrading reflex means resolving all of them together. A pinning strategy that holds reflex back but lets a component package float is a plausible source of resolution conflicts.
The third limitation is scope. There is no rollback story in the README: it documents init and run, and nothing about reverting a scaffold or downgrading a project. Teams that need a documented downgrade path will not find one in the README.
Finally, the README's own example depends on openai, which is not in the dependency list. The image generation snippet is illustrative code, not a supported integration; you supply that client yourself.
Where Reflex is the wrong tool
Reflex is the wrong choice when the frontend is the product. If your team already has designers shipping React components and a component library tuned to your brand, Reflex's Python component packages are an abstraction over that work, not a replacement for it, and you will spend effort mapping designs onto rx primitives instead of writing markup.
It is also the wrong choice for content-heavy sites. A blog, documentation site, or marketing page has almost no interactive state, and a stateful Python server sitting between the reader and the page adds an operational component for no benefit.
There is a subtler case: batch or CLI work. If the deliverable is a script or a scheduled job, nothing in Reflex's model helps, and the starlette, granian and socketio dependencies are pure overhead. The README frames the project around apps and hosting, and the repository includes a docker-example directory, which points at long-running services rather than one-shot processes.
Reflex against Streamlit and Gradio
The closest alternatives for a Python developer are Streamlit and Gradio, and the difference is in the execution model rather than the language.
Streamlit reruns the entire script top to bottom on every interaction. State lives in the script's variables and in session state, and the mental model is a notebook cell that re-executes. That is fast to write and awkward once you need a long-lived background task or fine control over which parts of the page update.
Gradio is built around a function signature: you define inputs and outputs, and the framework wires a UI to that function. It is excellent for model demos and poor for anything where the interface is not a form over a function.
Reflex takes a third position. State is an explicit class with typed fields and event methods, and the README's generate example shows an async handler that yields mid-flight to update the UI. That is a heavier abstraction than a script rerun, and it is the reason Reflex can express a multi-step workflow where a spinner and a partial result both matter. The cost is that you learn the State model, the @rx.event decorator, and the component packages before you ship anything.
Licence, release cadence and the cost of upgrading
Reflex is Apache-2.0, declared both in the repository's LICENSE file and as license.text in pyproject.toml. Apache-2.0 is a permissive licence with an explicit patent grant, and it does not require you to publish modifications. This is a description of the licence text, not legal advice; if you are redistributing Reflex inside a commercial product, have counsel read the actual terms.
The release history shows a rapid cadence. v0.9.9 landed on 2026-08-28, and the two alphas immediately before it, v0.9.9a1 and v0.9.9a2, were published the same day. The repository's last push was also 2026-08-28. That pattern, a stable release preceded by same-day alphas, suggests the project ships frequently and that the pre-release channel is active. It also means the upgrade cost is recurring rather than one-off.
The practical upgrade procedure is not documented in the README. What the repository does provide is a CHANGELOG.md at the top level, along with a news directory, which is where a team would look before bumping the version. The dependency floors on the component packages mean a reflex upgrade is really a coordinated upgrade of roughly a dozen packages; budget for it as a maintenance task, not a patch.
Editorial conclusion
Adopt Reflex if your team writes Python and the app is a stateful internal tool or dashboard where one language beats frontend flexibility. Do not adopt it if you need a frozen API surface, because pyproject.toml still carries the classifier Development Status :: 4 - Beta. Before committing, verify that reflex-components-radix and the rest of the component packages resolve against your pinned reflex version, and confirm the Python range requires-python = ">=3.10,<4.0" covers your interpreter.
Frequently asked questions
How do I install Reflex?
The README gives a uv workflow: create a directory, run uv init, then uv add reflex, then uv run reflex init and uv run reflex run. It recommends a virtual environment so the reflex command is on your PATH, and says the app then runs at http://localhost:3000.
What is Reflex in this context?
In this repository, Reflex is a Python library for building full-stack web apps in pure Python, with the frontend and backend both written in Python. It is unrelated to the medical or physiological senses of the word.
Which Python versions does Reflex support?
pyproject.toml sets requires-python to ">=3.10,<4.0" and the classifiers list Python 3.10 through 3.14. An interpreter outside that range will not resolve the package.
What licence is Reflex released under?
Apache-2.0, declared as license.text in pyproject.toml and included as a LICENSE file in the repository root. That is a permissive licence with a patent grant, but the project's own terms are the authority, not this summary.
Is Reflex production-ready?
The package metadata carries the classifier Development Status :: 4 - Beta, so the project labels itself as beta. The README does not document a rollback or downgrade procedure, and the component packages are versioned separately from reflex itself.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/reflex-dev-reflex)
Community notes