Skip to content

Next.js vs Remix vs React Router: Framework field

Compare Next.js, Remix, and React Router on navigation, data, and deploy axes , decision criteria without tribe membership.

5 min read
Next.js
Remix
React Router
Frameworks
SPA
SSR

Islands settled for content-heavy surfaces in the Astro post. When the product is a React app, authenticated workflows, nested layouts, mutations that own the UX - you need a framework that treats routing and data as first-class, not as plugins you assemble from blog posts.

The tribal version of this post is "Next vs Remix vs React Router." The useful version is three axes: navigation model, data/mutation model, and deploy surface. Pick on those. Logos come after.

What I am comparing (spring 2025)

  • Next.js (App Router): React meta-framework with file-based routes, Server Components by default, server actions / route handlers, and a strong Vercel affinity with portable Node/edge options.
  • Remix: nested routes, loaders/actions as the data story, progressive enhancement as a design center, adapters for many hosts.
  • React Router (framework mode / v7 lineage): the router library grown into a framework path, loaders/actions familiar to Remix users, Vite-centric tooling, SPA or SSR depending on how you assemble it.

React 19 is available (Dec 2024). RSC is stable in the Next App Router world. None of this makes Next mandatory, it makes "ignore RSC forever" a conscious choice, not an accident.

I am not ranking "best." I am naming failure modes of picking the wrong default for the job.

Axis 1: Navigation

NeedLean
Nested layouts with independent loading/error UIRemix / RR nested routes; Next layouts too
Soft navigations + browser-native forms as baselineRemix (and RR framework patterns)
Document-ish marketing + app under one roofNext (or Astro + a separate app, see Astro post)
Client-only SPA, own the server laterReact Router (library or SPA mode) + Vite

Next App Router navigation is powerful and opinionated (RSC payloads, soft nav). Remix/RR keep a clearer "URL → loader → UI" story that maps cleanly to HTTP. If your team thinks in fetch + cache layers already, RR/Remix feel like home. If your team thinks in "server components render trees," Next feels like home.

Axis 2: Data and mutations

Sketch of the Remix/RR mental model:

tsx
// app/routes/invoices.$id.tsx, illustrative Remix-style import type { LoaderFunctionArgs, ActionFunctionArgs } from '@remix-run/node'; import { Form, useLoaderData } from '@remix-run/react'; export async function loader({ params }: LoaderFunctionArgs) { const invoice = await db.invoice.find(params.id!); if (!invoice) throw new Response('Not found', { status: 404 }); return { invoice }; } export async function action({ request, params }: ActionFunctionArgs) { const form = await request.formData(); await db.invoice.update(params.id!, { status: String(form.get('status')), }); return null; // or redirect } export default function InvoiceRoute() { const { invoice } = useLoaderData<typeof loader>(); return ( <Form method="post"> <h1>{invoice.number}</h1> <select name="status" defaultValue={invoice.status} > <option value="draft">Draft</option> <option value="sent">Sent</option> </select> <button type="submit">Save</button> </Form> ); }

Next's App Router equivalent often splits across Server Components, route handlers, and server actions. That is more surface area and more power, also more ways to accidentally fetch on the client after the server already could have done it.

Decision criteria I actually use:

  1. Do mutations need to work without JS as a product requirement? → Remix / progressive-enhancement-first stacks win.
  2. Do we want RSC as the default composition model? → Next App Router.
  3. Do we already own a Vite SPA and need framework features without a rewrite religion? → React Router framework path is the least surprising migration for many Vite teams.

Axis 3: Deploy

ConstraintImplication
Team already on Vercel, happy with itNext friction is low
Must run on Cloudflare / custom Node / FlyCheck adapters; Remix and RR are often clearer multi-host stories
Edge-only, tiny cold startsPrototype the real host early, not localhost Express
Static export onlyNext can do it with constraints; Astro may still be the content answer

"Deploy later" is how you discover your framework's Node APIs do not exist on Workers. I treat host choice as a week-one spike, not a launch surprise.

Continuity with the SPA / Vite SSR posts

  • Vanilla Vite SPA: own everything, ship fast for authenticated tools.
  • Vite SSR plugins: HTML for a few routes without full meta-framework overhead.
  • Astro islands: content default, React as guest.
  • This post: React app is the product, pick the framework that matches navigation + data + host.

If you are still arguing frameworks before scoring SPA vs MPA, go back two weeks. Framework choice is downstream of architecture.

Failure modes

Choosing Next because "everyone uses it." The talent pool is real; so is RSC education cost for a team that only knows CSR.

Choosing Remix/RR and then rebuilding RSC patterns by hand. You wanted Next's model; admit it.

SPA-mode forever with no loader discipline. You bought a framework and kept useEffect waterfalls. The router was not the bottleneck, the data model was.

Ignoring React Router's dual identity. Library vs framework mode are different products. Name which one you adopted in the README.

Decision table

If your center of gravity is…Default
RSC + server-first React UINext App Router
Nested routes + loaders/actions + formsRemix or RR framework
Vite SPA migrating upward graduallyReact Router (framework)
Content with a few widgetsAstro (not these three)
Full control, small team, minimal stackVite CSR ± targeted SSR

Takeaway

Next, Remix, and React Router are not personalities, they are bets on navigation, data, and deploy. Score the product on those axes, then pick the stack that matches. Tribe membership is not a deploy strategy.