Remix 3 Abandons React, TanStack Start 1.0 Arrives: Two Full-Stack Philosophies Compared
The article compares TanStack Start 1.0 and Remix 3.0, two major October releases: TanStack Start builds on a type-safe router with SSR, streaming, end-to-end types, and server functions, while Remix 3 rewrites as a React-agnostic framework using Fetch API routing, Frames, and unbundling, but with no upgrade path and loss of the React ecosystem.
TanStack Start 1.0: Bringing the SPA Development Experience to Full-Stack
TanStack Start 1.0 is built on TanStack Router, a type-safe router extended with full-stack capabilities. Its 1.0 release delivers:
Full-document SSR + streaming
End-to-end types
Server functions and cross-stack middleware
Dual framework support for React and Solid
Deployment-agnostic
The team profiled the SSR hot path, removed unnecessary server-side computation, and achieved roughly a 5.5x throughput improvement in benchmarks—a concrete number more useful than vague "faster framework" claims.
The trade-off is a lower abstraction level: routing conventions, cache invalidation (Query), and auth middleware must be assembled manually; the ecosystem is far smaller than Next.js, so many "batteries-included" features require custom implementation.
Remix 3.0: It Is No Longer a React Framework
Remix 3's release notes open with a striking phrase: "single dependency." This is a ground-up rewrite, not an upgrade. The original Remix 2 has been merged into React Router, while the Remix name now belongs to a new framework:
No longer depends on React
Routing based on Fetch API
Frames
Unbundling
Single-package full-stack
It focuses on web primitives and "letting agents write correct code too."
The cost: no upgrade path from Remix 2 (migration equals rewrite); the React ecosystem (Radix, shadcn, countless component libraries) becomes unusable; the community's main criticism is trust erosion from repeated rewrites—the official stable path remains React Router.
Same Task, Two Implementations
A counter example illustrates three key differences:
// Remix 3: state is a plain field, explicit notification after mutation
class Counter {
count = 0;
increment() {
this.count += 1;
this.update(); // no setState, no dependency tracking
}
} // TanStack Start: still React, server-side data fetching but component unchanged
const getTodos = createServerFn().handler(() => db.todo.findMany());
export const Route = createFileRoute('/todos')({
loader: () => getTodos(), // runs on server
component: () => {
const todos = Route.useLoaderData(); // types inferred automatically
return <ul>{todos.map(t => <li key={t.id}>{t.title}</li>)}</ul>;
},
});The former spreads complexity out for you to see; the latter absorbs complexity into the framework. Neither is more "advanced"—only which fits your team better.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JavaScript
Provides JavaScript enthusiasts with tutorials and experience sharing on web front‑end technologies, including JavaScript, Node.js, Deno, Vue.js, React, Angular, HTML5, CSS3, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
