React to Reflex: Unnecessary Abstraction Hell

january 24, 2026

A journey from React to Python's Reflex framework, exploring the pitfalls of unnecessary abstractions and the value of using the right tool for the job.

Engineering · python · react · reflex · web-development

From React to Reflex: A Journey Through Unnecessary Abstraction Hell

Or: How I Learned to Stop Worrying and Hate Python Web Frameworks

Why Reflex

So there I was with a perfectly functional React + Vite dashboard. Clean code, fast builds, straightforward TypeScript. Life was good. The dashboard worked. Users were happy. Then the worst kind of idea showed up: "Let's rewrite this in Python." (I was the one who said it. I have no one else to blame.)

Why? Because I was bored. Because "full-stack Python" sounds clean on paper to people who have never actually shipped full-stack Python. Because apparently I needed a very concrete, 400-line lesson in the cost of unnecessary abstraction.

The Migration Begins

"It'll be easy," the docs said. "Reflex is just Python," the GitHub readme said. "You won't even need to touch JavaScript," tech Twitter said.

Narrator: It was not easy, it was not just Python, and the JavaScript simply hid in the shadows, waiting.

What I Expected

python
# Beautiful, Pythonic code that definitely just works
def dashboard():
    return render_my_beautiful_ui()
# Beautiful, Pythonic code that definitely just works
def dashboard():
    return render_my_beautiful_ui()

What I Got

python
# This is literally just React with extra steps and worse autocomplete
def business_row(business: dict) -> rx.Component:
    return rx.table.row(
        rx.table.cell(
            rx.hstack(
                rx.box(
                    rx.icon("building-2", size=18, style={"color": COLORS["mauve"]}),
                    style={"background": COLORS["surface0"]},
                    class_name="w-10 h-10 rounded-full flex items-center justify-center",
                ),
                # ... 50 more lines of this absolute nonsense
# This is literally just React with extra steps and worse autocomplete
def business_row(business: dict) -> rx.Component:
    return rx.table.row(
        rx.table.cell(
            rx.hstack(
                rx.box(
                    rx.icon("building-2", size=18, style={"color": COLORS["mauve"]}),
                    style={"background": COLORS["surface0"]},
                    class_name="w-10 h-10 rounded-full flex items-center justify-center",
                ),
                # ... 50 more lines of this absolute nonsense

Wait a minute... class_name? style? rx.hstack? Bro, this is just JSX wearing a Python trench coat!

The Wrapper Nightmare

The "Python" Experience

Let me tell you about the "Python coding experience" I was promised versus what I received:

String Concatenation? LOL Skill Issue

Remember simple string concatenation? Yeah, forget about it. That's a legacy feature now.

Before (React):

jsx
<img src={`https://s3.amazonaws.com/${image}`} />
<img src={`https://s3.amazonaws.com/${image}`} />

After (Reflex):

python
rx.image(
    src="https://s3.amazonaws.com/" + log["personImage"].to(str),
    # Because apparently log["personImage"] isn't a string.
    # It's a Var. A special Reflex type.
    # That you need to explicitly convert to a string.
    # In Python.
    # The language literally famous for "duck typing".
)
rx.image(
    src="https://s3.amazonaws.com/" + log["personImage"].to(str),
    # Because apparently log["personImage"] isn't a string.
    # It's a Var. A special Reflex type.
    # That you need to explicitly convert to a string.
    # In Python.
    # The language literally famous for "duck typing".
)

Empty Strings? Straight to Jail.

My absolute favorite error message of the week:

text
Error: A <Select.Item /> must have a value prop that is not an empty string.
Error: A <Select.Item /> must have a value prop that is not an empty string.

So I had to create a special __all__ value and convert it back to an empty string in the state handler. In Python. The language where "" evaluates to False and is universally accepted. But no, the underlying React component was offended, thus the Python wrapper threw a tantrum. Beautiful architecture.

The Styling Nightmare

"Use Tailwind!" they said. So I did. But here's the kicker: I am writing Tailwind classes. In Python strings. That get compiled to React. That renders HTML.

python
class_name="rounded-xl border p-5 hover:border-[#45475a] transition-colors duration-200"
class_name="rounded-xl border p-5 hover:border-[#45475a] transition-colors duration-200"

This is HTML with extra steps. I could be writing this in a .tsx file with proper syntax highlighting, autocomplete, and type checking via the Tailwind VS Code extension. Instead, I'm writing it in Python strings where my IDE just thinks I'm typing a very long, very sad novel.

The Build Process

Waiting for Build

React + Vite:

  • npm run dev - 200ms startup. I sneeze and it's running.
  • Hot reload - instant.
  • Build - 2 seconds.

Reflex:

  • reflex run - Wait for Python to start.
  • Wait for Reflex to compile the AST.
  • Wait for the frontend to build (it spins up Node anyway!).
  • Wait for the backend to start.
  • Oh, you changed a component's padding? Let's recompile everything!
  • Port 8000 already in use? Cool, we'll use 8001. Now your API calls fail.
  • Hope you like seeing deprecation warnings about Pydantic v1!

The "Benefits" of Reflex Over React

Here is the complete, unabridged list of benefits from using Reflex instead of React:

  1. You can write "Python" instead of JavaScript.
  2. ...
  3. That's it. That's the list.

That's the full value proposition. Except you're not actually writing Python. You're writing React component trees using Python syntax. You still have to think in components, props, and state hooks. You still write Tailwind strings. The only thing that changed is the language you're doing it in, and that language is demonstrably worse at this specific task because it wasn't built for the DOM.

The only real differences are:

  • Worse error messages (because the stack trace crosses a language barrier)
  • Slower build times (you run Python AND Node)
  • A massive abstraction layer you cannot debug
  • Documentation that's "still rapidly evolving"

The Reality Check

Here's the final tally:

React vs Reflex

Before (React):

  • 260 lines of TypeScript
  • Fast development
  • Immediate feedback loop

After (Reflex):

  • 456 lines of Python
  • Var types that pretend to be Python but actually just output JS strings
  • Slower development
  • It still compiles to React anyway.

Reflex Code IDE

Why Does This Framework Exist?

Honest question. The pitch is "write web apps in Python!" The reality is "write React in Python syntax while fighting type systems that don't make sense and watching build times measured in geological epochs."

If you want Python, write Python! FastAPI. Django. Jinja. HTMX if you need interactivity without writing JS. Those tools are proven, fast, and designed for the exact task they perform.

If you want a modern SPA, write React. Or Vue. Or Svelte.

Don't use a framework trying to be both that ends up failing at both.

The Conclusion (Hot Take Edition)

Would I recommend Reflex? Only if you:

  • Actively enjoy debugging type systems that shouldn't exist.
  • Need an excuse to go make coffee while your frontend compiles.
  • Think "it's Python so it must be simpler" is a valid architectural decision and not just a coping mechanism.

For everyone else: just learn React. It takes a weekend. A single weekend. You will be infinitely more productive, you will have better tooling, and you won't find yourself casting variables to strings before you can concatenate them.

The Irony

After all of this migration work, the final deployed app still:

  • Runs in a browser.
  • Uses React under the hood.
  • Requires Node.js in the build pipeline.
  • Needs JavaScript to execute on the client.

We added Python as a middleman. Python, the language, is acting as a glorified transpiler for React. Congratulations, we played ourselves.


If you're a Python developer who wants to build web apps, I have two suggestions:

  1. Learn React. It's not that hard. There are millions of tutorials.
  2. Stick to what Python is good at. Backend APIs, data processing, machine learning. Let JavaScript handle the DOM. That is what it is for.

If you enjoy looking at code that shouldn't exist, here's the project I migrated:


Written while waiting for Reflex to recompile for the 47th time today.

back to blog