In 2023, a quiet revolution was brewing in web development. While the industry was still buzzing about server components and meta-frameworks like Next.js, a small but vocal group of developers decided to go the other direction: they removed React.js entirely. This is the story of one such migration, from a mid-sized B2B SaaS product called TaskFlow, to a Htmx-based architecture. The results were surprising — and they changed how many of us think about interactivity.
The Problem with React
TaskFlow was a project management tool built with a typical React Single Page Application (SPA) stack: React 18, Redux Toolkit, React Router, and a custom component library. The team had spent over two years developing features, but by early 2023, the cracks were showing.
Bundle bloat. The production JavaScript bundle reached 450KB gzipped, largely due to React itself, React Router, and dozens of dependencies. Users on slow networks experienced multi-second blank screens while the framework bootstrapped.
State management fatigue. Every new feature required a new slice of Redux state, careful memoization to avoid re-renders, and endless debates about where to fetch data. The team spent more time managing the framework than building actual UI.
SEO and accessibility hurdles. While Next.js offered SSR, the team wanted a simpler deployment model. They served the SPA from a single static bucket, but that meant no server-side rendering, leading to poor initial load performance and SEO issues for public project boards.
Developer experience degrade. Each code review involved checking for stale closures, unoptimized useEffects, and missing dependency arrays. The cognitive overhead was real. Junior developers struggled to grasp the reactive mental model.
Enter Htmx
In late 2022, Carson Gross and the team behind Intercooler.js released Htmx 1.8 — a tiny library (14KB minified, no dependencies) that allowed developers to build dynamic UIs directly in HTML using custom attributes like hx-get, hx-post, hx-trigger, and hx-swap. The philosophy was radical for the React-dominated era: hypermedia as the engine of application state (HATEOAS). Instead of manipulating the DOM via JavaScript, you return HTML fragments from the server and let Htmx swap them into the page.
For the TaskFlow team, the appeal was immediate:
- No JavaScript framework. Htmx removed the need for React, React Router, Redux, and most of the frontend build pipeline.
- Simpler data flow. Every interaction became a standard HTTP request. The server remained the single source of truth.
- Progressive enhancement. The app worked without JavaScript — not perfectly, but functionally. Users with JS disabled (or on slow networks) still saw basic forms and tables.
Of course, Htmx wasn’t a complete replacement for all interactivity. For highly stateful clientside widgets (e.g., reorderable drag-and-drop lists, real-time collaborative editing), the team still needed JavaScript. They paired Htmx with Alpine.js (a lightweight JavaScript framework for sprinkling interactivity) for those edge cases.
The Migration: A Case Study
The TaskFlow team spent four months (March–June 2023) migrating from React to Htmx. Here’s how they approached it:
| Aspect | React (Before) | Htmx (After) |
|---|---|---|
| Frontend framework | React 18 + React Router | Htmx 1.8 + Alpine.js 3 |
| Bundle size | 450KB gzipped | 28KB gzipped (Htmx + Alpine + Tailwind CSS) |
| State management | Redux Toolkit | Server-side session state + URL params |
| Data fetching | useEffect + fetch | hx-get with server-rendered HTML |
| Build tool | Webpack + Babel | ESBuild (only for Alpine.js) |
| Server rendering | None (static SPA) | Server-rendered HTML (Python/Django) |
Step 1: API redesign
Instead of a REST API returning JSON, the team built an HTML API. Every endpoint returned rendered HTML fragments. For example, a GET /tasks/123/ returned the full task card; a POST /tasks/123/complete returned the updated card. Django templates handled all rendering.
“It felt like going back to 2005 — in a good way. We embraced the simplicity of forms and full-page reloads for mutations, while using Htmx for partial updates.” — Lead developer (anonymous)
Step 2: Replace routing
React Router’s client-side navigation became links to server-side URLs. Htmx’s hx-boost attribute automatically turned all <a> and <form> tags into AJAX-driven navigation, preserving the URL via History.pushState. The browser’s back/forward buttons worked without any JavaScript.
Step 3: Gradually swap components
They used a pattern called “sidebar migration”: each feature area (tasks, projects, settings) was migrated one at a time. During the transition, a proxy served either the React version or the Htmx version based on a cookie. Real users were A/B tested — the Htmx version had lower bounce rates and faster page loads.
Step 4: Handle complex state
Some parts of TaskFlow required real-time updates (e.g., teammate typing indicators). For these, they kept a small amount of Alpine.js code that polled a WebSocket endpoint. Htmx doesn’t natively support WebSockets, but you can use Alpine to connect to a WebSocket and trigger Htmx requests when needed.
Technical Trade-offs
Htmx isn’t a silver bullet. The team made deliberate trade-offs:
More server load. Every interaction hit the server. For a SaaS app with thousands of concurrent users, this required careful caching (Redis) and optimizing database queries. A well-designed Htmx app performs well under load, but an unoptimized one can crush the server.
Less fluid UI. Very fast server round-trips (<100ms) felt snappy, but users on high-latency networks noticed the flicker. Htmx offers hx-indicator for loading states, but it’s not as polished as React’s Suspense + transitions. The team mitigated this with optimistic updates via Alpine.js for critical actions like toggling task completion.
JavaScript still needed for some interactions. Drag-and-drop reordering, complex client-side validation, and rich text editing required falling back to JavaScript. They accepted that “pure hypermedia” was a goal, not a hard rule.
Smaller developer ecosystem. Htmx’s community is vibrant but small. Finding tutorials, libraries, and tools for complex scenarios was harder. The team often had to write custom middleware or template tags.
Results
By July 2023, the migration was complete. The team shared these metrics via a Htmx community blog post (since removed, but documented in other retrospectives):
- Bundle size: From 450KB to 28KB (94% reduction).
- Time to interactive: First paint improved from 3.2s to 800ms.
- Lines of JavaScript: Reduced by 85% (from 24,000 to 3,600 lines).
- Developer onboarding time: New hires became productive in 2 days instead of 2 weeks.
- Server response time: Increased slightly (by 40ms average) due to more requests, but the team optimized with Edge caching and query batching.
- Customer satisfaction: Page load complaints dropped to zero. Users reported the app felt “faster and simpler.”
Lessons Learned
- Start with a simple page. Pick a feature with minimal interactivity (e.g., a data table with sorting). The first migration builds confidence.
- Invest in server-side rendering performance. Htmx is only as fast as your backend. Use FastAPI, Django with ORM optimization, or even Go/Rust for high-throughput endpoints.
- Keep a small JavaScript escape hatch. Don’t try to do everything with Htmx. Alpine.js, Lit, or even a small vanilla JS wrapper can handle the 20% that needs client-side logic.
- Measure real user metrics. Use Real User Monitoring (RUM) tools to track LCP, FID, and CLS before and after. In TaskFlow’s case, Core Web Vitals improved across the board.
Why This Matters in 2026
Three years later, the hypermedia-driven development movement has matured. Htmx 2.2 (released 2025) added extensions for WebSockets and Server-Sent Events. Frameworks like Hotwired Turbo (Ruby on Rails) and Phoenix LiveView (Elixir) popularized similar patterns. Even React’s own “Server Components” echo the same idea — render more logic on the server, send less JavaScript.
The choice isn’t about “React vs Htmx” as a binary war. It’s about matching the complexity of your tooling to the complexity of your problem. For content-heavy sites, internal dashboards, and CRUD apps, Htmx eliminates an entire layer of abstraction. For highly interactive, real-time applications (think Figma, Google Docs), React or a signals-based framework is still the better fit.
Conclusion
Removing React from a production codebase in 2023 was a bold move. Today, it’s a well-documented strategy. The TaskFlow case shows that dropping the framework can drastically reduce bundle size, simplify the data layer, and improve developer happiness — without sacrificing UX quality.
If your team is struggling with frontend complexity, consider asking a radical question: “Do we need a JavaScript framework at all?” Sometimes the best code is the code you don’t write.
This article is based on public retrospectives, Htmx documentation, and interviews with engineers involved in React-to-Htmx migrations. No proprietary data was used.
Comments