The Billion Dollar JSX Mistake

5 min read Original article ↗

Resti Guay

How React’s Template Revolution Accidentally Created a Developer Productivity Crisis

A 4-minute read that might change how you think about frontend architecture

In 2013, React introduced JSX and changed everything. For the better, we thought. Ten years and countless developer hours later, I’m starting to wonder if we made a billion-dollar mistake.

Don’t get me wrong — JSX was revolutionary. It made components feel natural, brought HTML-like syntax to JavaScript, and helped millions of developers build complex UIs. But somewhere along the way, we traded architectural clarity for template convenience.

And the cost has been staggering.

The Hidden Tax of Template Thinking

Every day, developers around the world open React codebases and play a game I call “Component Archaeology.” You know the drill:

  1. See a conditional render: {user ? <Dashboard /> : <Login />}
  2. Wonder: “What does <Dashboard /> actually render?"
  3. Navigate to Dashboard.jsx
  4. Find more conditionals: {loading ? <Spinner /> : data ? <Content /> : <Error />}
  5. Wonder: “What does <Content /> render?"
  6. Navigate to Content.jsx
  7. Repeat ad infinitum

This isn’t development — it’s digital archaeology. We’re constantly excavating layers of abstraction to understand what our applications actually do.

The Real Cost

Let’s do some napkin math. Say the average React developer spends just 30 minutes per day navigating component hierarchies to understand application flow. That’s 2.5 hours per week, 130 hours per year.

With over 10 million React developers worldwide, we’re talking about 1.3 billion hours annually spent on component navigation. At an average developer salary of $100/hour, that’s $130 billion per year in lost productivity.

Just from playing hide-and-seek with our own code.

The Architecture We Accidentally Built

JSX encouraged us to think in templates, but complex applications aren’t templates — they’re state machines with conditional flows. Yet our code doesn’t reflect this reality.

Here’s what a typical React component actually represents:

function App() {
if (loading) return <LoadingSpinner />;
if (error) return <ErrorPage />;
if (!user) return <LoginForm />;
if (user.role === 'admin') return <AdminDashboard />;
if (route === '/profile') return <ProfilePage />;
return <HomePage />;
}

This is a state machine. But it’s disguised as a template, scattered across dozens of files, each hiding their own conditional logic.

What if we stopped pretending this was a template and started treating it like the architectural pattern it really is?

The Object-First Alternative

What if we stopped pretending this was a template and started treating it like the architectural pattern it really is?

I’ve been experimenting with a different approach — one that treats UI as data structure composition rather than template rendering. Instead of hiding logic in templates, we expose the entire application flow:

javascript// Authentication + Route + Permission + Async - all visible
const authFlow = {
condition: () => isAuthenticated(),
whenTrue: {
'/dashboard': {
allowedRoles: ['user', 'admin'],
authorized: {
loading: () => isLoading(),
loadingState: 'LoadingSpinner',
successState: 'Dashboard',
errorState: 'ErrorBoundary'
},
unauthorized: 'UpgradePlan'
},
'/profile': 'ProfilePage',
fallback: 'NotFoundPage'
},
whenFalse: 'LoginForm'
};

This declarative structure makes the entire flow immediately comprehensible. No navigation required. No mental stack management. Just clear architectural intent.

The Component Injection Pattern

This approach separates control flow logic from UI components. Instead of burying conditional logic inside templates, we declare it explicitly:

// Before: Hidden complexity
<AuthGate>
<DashboardRoute>
<PermissionBoundary>
<AsyncData>
<SomeComponent />
</AsyncData>
</PermissionBoundary>
</DashboardRoute>
</AuthGate>

// After: Explicit flow
const flow = {
authenticated: {
dashboard: {
hasPermission: {
loading: 'Spinner',
success: 'SomeComponent',
error: 'ErrorPage'
},
noPermission: 'UpgradePage'
}
},
unauthenticated: 'LoginPage'
};

The second version is self-documenting. Every possible path is visible. Every component that might render is explicit.

The Readability Revolution

This isn’t just about syntax — it’s about cognitive architecture. When your code structure mirrors your application’s decision tree, debugging becomes trivial:

  • Bug in authentication? Look at the authenticated branch
  • Permission issue? Check the hasPermission logic
  • Loading state problem? Find the AsyncData configuration
  • Wrong component rendering? Trace the exact path

No more component archaeology. No more mental stack management. Just clear, architectural code that documents itself.

Beyond Templates

We’ve spent a decade optimizing template rendering — virtual DOMs, fiber reconciliation, concurrent features. But what if the real performance bottleneck isn’t runtime rendering, but developer comprehension?

What if the path to faster development isn’t better templates, but better architecture?

The object-first approach suggests we might have been solving the wrong problem. Instead of making templates faster, what if we made applications readable?

The Road Ahead

I’m not suggesting we abandon React or JSX. They’ve enabled incredible innovation and will continue to power amazing applications. But maybe it’s time to question some assumptions.

Maybe the future of frontend development isn’t better templates, but declarative architecture — code that reads like a blueprint rather than a mystery novel.

Maybe instead of optimizing for rendering performance, we should optimize for comprehension performance.

Maybe the billion-dollar mistake wasn’t adopting JSX, but assuming it was the final answer.

What do you think? Have we been solving the wrong problem? Are there other architectural patterns that could improve developer productivity? Share your thoughts in the comments below.

Follow me for more explorations into frontend architecture and developer productivity. The next article will dive deeper into practical implementation strategies for declarative UI patterns.