Reflex: Building Full-Stack Web Apps in Pure Python
Reflex lets you build complete web applications — frontend, backend, and database — without leaving Python. Unlike dashboard-oriented tools, Reflex compiles your Python components into a React/Next.js frontend while running your application logic on a FastAPI backend, giving you genuine state management, routing, and persistence. This tutorial walks through the architecture, the state model, components, routing, async handlers, database access, and deployment using a coherent task-manager example.
What Reflex Is and How It Works
Reflex (formerly Pynecone) is a framework for building full-stack web apps where you write only Python. At build time, the components you describe in Python are compiled into a React/Next.js frontend. At runtime, your application state lives in Python classes that execute on a FastAPI backend. The browser and the backend communicate over a WebSocket connection: user interactions trigger event handlers on the server, the server mutates state, and only the changed state is pushed back to the client, which re-renders the affected components.
This is a different model from Streamlit. In Streamlit, every interaction re-runs your entire script top to bottom, and you manage persistence through st.sessionstate. Reflex instead keeps a long-lived state object per client session and updates the UI reactively — only the parts bound to changed state vars update. You get a single-page-application feel with client-side routing, plus a real backend you can attach databases and background tasks to.
Architecture at a Glance
- Frontend: Python components compile to React components rendered by Next.js. Styling maps to CSS/Tailwind under the hood.
- Backend: A FastAPI server hosts your
Stateclasses and event handlers. - Transport: A WebSocket carries events from client to server and state deltas back.
- Database (optional): Built-in SQLModel integration (SQLite by default) accessible from event handlers.
Browser (React/Next.js) <-- WebSocket --> FastAPI backend (Python State + handlers)
|
Database (SQLModel)
Installation and Project Setup
Reflex requires Python 3.10 or newer. Create an isolated environment, then install the package.
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install reflex
Verify the installation
reflex --version
Initialize a new project inside an empty directory. The init command scaffolds the structure and prompts you to pick a template; choose the blank template to start clean.
mkdir taskmanager && cd taskmanager
reflex init
When prompted, select the "blank" template
Project Structure
After initialization you get a layout similar to this:
taskmanager/
├── taskmanager/
│ └── taskmanager.py # Your app: state, components, pages
├── assets/ # Static files (images, favicon)
├── rxconfig.py # App configuration (name, dburl, etc.)
└── requirements.txt
The rxconfig.py file declares the app name and configuration such as the database URL and frontend/backend ports.
import reflex as rx
config = rx.Config(
appname="taskmanager",
dburl="sqlite:///taskmanager.db",
)
Running in Development
Start the development server. Reflex compiles the frontend, launches the FastAPI backend, and serves the app with hot reload.
reflex run
Frontend on http://localhost:3000, backend on http://localhost:8000
The State Model
State is the core of Reflex. You define state by subclassing rx.State. Class attributes with type annotations become state vars — reactive values stored per client session. Methods on the state class are event handlers: they run on the backend and are the only place you should mutate state.
import reflex as rx
class CounterState(rx.State):
count: int = 0
def increment(self):
self.count += 1
def decrement(self):
self.count -= 1
def setcount(self, value: str):