Remix released its version 3 beta on April 29, abandoning React entirely for a ground-up rewrite. This isn’t an upgrade—it’s a different framework. Remix now uses a fork of Preact and an imperative programming model that trades React’s ecosystem for web standards simplicity. Controversial? Absolutely. But if you’re tired of hook complexity and Server Components overhead, here’s how to build with it.
Why Remix Abandoned React
The Remix team identified four principles for v3: model-first development, prioritize web APIs, runtime over build steps, and minimal dependencies. React no longer fit those principles. Chasing React’s roadmap—hooks, Server Components, the constant evolution—meant Remix couldn’t own its stack. So they forked Preact and built a simpler model.
The community is divided. “I have never, in my entire career, seen a library change as many times as React Router,” one Hacker News user wrote. Others see promise: “This could be the next big thing. Only good things can come from research like this.” Shopify’s backing means Remix can experiment without VC pressure to chase trends.
React fatigue is real. If you’ve fought with useEffect dependency arrays or debugged Server Components, the appeal is obvious. Remix 3 offers an escape—at the cost of React’s massive ecosystem.
The New Programming Model
Remix 3 replaces React’s declarative hooks with imperative, mutable state. Instead of useState, you mutate values directly and call this.update() to trigger re-renders. It maps closer to how browsers actually work.
React approach:
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
Remix 3 approach:
this.count = 0;
const increment = () => {
this.count += 1;
this.update(); // Explicit
};
The difference: React hides complexity in the framework (hook rules, dependency tracking, reconciliation). Remix exposes it explicitly—you mutate, you update, you control the flow. No magic.
Remix 3 also ditches synthetic events for native browser events. No more onClick props—you use addEventListener with EventTarget. Forms submit with standard <form method="post">, not onSubmit handlers. It’s closer to the platform, which means less abstraction but more boilerplate for complex interactions.
The trade-off: React’s declarative model makes UI predictable and composable. Remix’s imperative model makes data flow explicit and debuggable. Pick your complexity.
HTML-over-the-Wire with DOM Morphing
Remix 3 sends HTML fragments from the server, not JSON. When a section of the page updates, the server returns new HTML, and Remix “morphs” the DOM to match—preserving focus, scroll position, and state without a page reload.
This is different from React’s virtual DOM diffing. React compares virtual trees in memory and patches the real DOM. Remix skips the virtual layer entirely. The server sends HTML, the client morphs directly. Smaller bundle, closer to how HTMX works.
The Frame component enables this pattern. A Frame is a section of the page that loads independently. When it refreshes, Remix fetches new HTML and morphs just that section. Progressive enhancement means forms work even if JavaScript fails.
Setting Up Your First Project
Prerequisites: Node.js 18+ or Bun. Remix 3 is experimental, so install packages with the @experimental tag:
npm install @remix-run/dev@experimental @remix-run/node@experimental
Alternatively, use Bun for faster builds:
bun install @remix-run/dev@experimental @remix-run/node@experimental
The project structure is simpler than React Router. No complex config, no webpack wrangling. Remix ships with sensible defaults optimized for web standards.
For a working example, check Sergio Daza’s remix-v3-demo on GitHub. It demonstrates a hydrated counter using Remix UI components instead of React, leveraging Bun’s built-in bundler and importmaps for dependencies.
Form handling follows web standards. Use a standard <form> element with method="post". The server action handles the mutation and returns HTML. Remix morphs the DOM to reflect changes. No client-side state management, no fetch wrappers—just forms and responses.
When to Use Remix 3
Remix 3 is experimental. Beta status means it’s ready to experiment with, not ship to production.
Use Remix 3 if:
- Green field project with no migration burden
- Simple to medium app—CRUD dashboards, content sites
- You want a simpler mental model than React hooks
- You tolerate API churn and beta instability
Avoid Remix 3 if:
- Existing React or Remix 2 codebase (no migration path)
- Enterprise app requiring stability
- You need React’s component ecosystem
- Production deadline looms
The comparison: Next.js is battle-tested for enterprise. SvelteKit delivers smaller bundles with a stable release. Remix 3 is the experimental playground for developers tired of React complexity. If you’re already on Remix 2, the upgrade path is React Router 7—it keeps React while absorbing Remix features like loaders and actions.
Remix 3 trades ecosystem for simplicity. That’s not wrong, but it’s a choice. If you rely on React libraries—UI kits, animation frameworks, form validators—you lose access. If you value web standards and explicit control, you gain clarity.
Key Takeaways
- Remix 3 uses imperative state (
this.update()) instead of React hooks - HTML-over-the-wire with DOM morphing replaces virtual DOM diffing
- Experimental status means beta-testing only, not production-ready
- Best for green field projects and developers escaping React fatigue
- No migration path from Remix 2—use React Router 7 instead
Remix 3 won’t replace React tomorrow. But it’s an interesting signal that framework churn and complexity have consequences. Watch this space—if it reaches stability, it could become the pragmatic alternative React refugees have been waiting for.











