Skip to content

React8 min read

Vite vs Next.js vs React Router: Choosing a React Stack

Vite vs Next.js vs React Router framework mode in 2026: compare rendering, routing, data loading, SEO and hosting to pick the right React stack for you.

For most new React projects in 2026, the choice is simple: pick Next.js for public, SEO-sensitive or full-stack apps, pick React Router in framework mode if you want server rendering with a lighter, web-standards approach on top of Vite, and pick plain Vite for client-only apps behind a login. All three are production-ready. The real question is where your HTML gets rendered and how much framework you want to own.

Key takeaways

  • Vite is a build tool, not a framework. A Vite React app is a client-rendered SPA unless you add SSR yourself.
  • Next.js 16 gives you React Server Components, Server Actions, Turbopack by default and explicit caching with Cache Components.
  • React Router v8 framework mode is a Vite plugin with type-safe route modules, loaders and actions, and SPA, SSR or pre-rendered output.
  • Public pages that must rank in search should be server-rendered or pre-rendered. Dashboards behind auth usually do not need it.
  • Create React App is deprecated. The React docs recommend a framework, or building from scratch with a tool like Vite.

Current versions at a glance

As of late October 2026, the current stable lines are:

  • Vite 8, released in March 2026, which replaced the esbuild plus Rollup pairing with Rolldown as its single bundler. It needs Node.js 20.19+ or 22.12+.
  • Next.js 16, with Turbopack as the default bundler for dev and production, proxy.ts replacing middleware.ts, and stable React Compiler support. It needs Node.js 20.9+.
  • React Router v8, released in June 2026. It is a deliberately small major release: ESM-only, react-router-dom removed in favour of react-router, and v7 future flags (including middleware) now on by default. It requires Node 22.22+, React 19.2.7+ and, in framework mode, Vite 7 or later.

Vite vs Next.js vs React Router: the comparison

Vite (React SPA) React Router v8 (framework mode) Next.js 16 (App Router)
What it is Build tool and dev server Router plus framework, as a Vite plugin Full-stack React framework
Default rendering Client-side only SSR, with SPA mode and pre-rendering options Server Components with streaming SSR
Static output Yes (always) Yes (ssr: false or prerender) Yes (output: "export", with limits)
React Server Components No Unstable / opt-in Stable, the default
Data loading Your choice (TanStack Query, fetch) Route loader and action functions async Server Components, Server Actions
Routing Add a router yourself Config-based routes.ts File-system routing (app/)
Bundler Rolldown (Vite 8) Vite Turbopack (webpack opt-in)
Hosting Any static host or CDN Node server, or adapters for platforms like Cloudflare, Vercel, Netlify Vercel, Node server, Docker, static export
Learning curve Lowest Medium Highest
Best for Dashboards, admin panels, internal tools, embedded widgets Web apps that want SSR and web-standard forms without RSC complexity Marketing sites, ecommerce, content, SaaS with public pages

When plain Vite is the right choice

Terminal
npm create vite@latest my-app -- --template react-ts

Vite gives you a fast dev server, hot module replacement, and an optimized static build. Everything else, routing, data fetching, auth, is your decision.

That is a feature, not a flaw, for apps where:

  • Every screen sits behind a login, so search engines never see it.
  • You deploy to a CDN or object storage and do not want a Node server.
  • The backend already exists (a REST or GraphQL API, maybe in another language).
  • You are building an embeddable widget or a PWA that runs mostly offline.

A typical stack is Vite + React Router (declarative or data mode) + TanStack Query. That covers most internal tools well. If you go this route, make the data layer solid; the TanStack Query guide covers the patterns.

The trade-offs

  • SEO. The server sends an almost empty HTML shell, and content appears after JavaScript runs. Google can render JavaScript, but it is slower and less reliable than serving HTML, and many other crawlers and link previewers do not render at all. I explain the details in why your React SPA is not ranking.
  • Initial load. The browser must download and run your bundle before showing real content, which hurts LCP on slow devices.
  • Request waterfalls. Components fetch after they render, and child components fetch after their parents. Route-level loaders or prefetching help.

When to choose React Router framework mode

Terminal
npx create-react-router@latest my-app

React Router's framework mode is what Remix v2 became: the Remix features were merged into React Router, and it runs as a Vite plugin. You define routes in routes.ts, and each route module can export a loader (runs before render, on the server in SSR mode), an action (handles form submissions), meta and an error boundary. Generated types make loaderData and params type-safe.

TypeScript
// app/routes.ts
import { type RouteConfig, index, route } from "@react-router/dev/routes";

export default [
  index("routes/home.tsx"),
  route("products/:id", "routes/product.tsx"),
] satisfies RouteConfig;
TSX
// app/routes/product.tsx
import type { Route } from "./+types/product";

export async function loader({ params }: Route.LoaderArgs) {
  const res = await fetch(`https://api.example.com/products/${params.id}`);
  if (!res.ok) throw new Response("Not found", { status: 404 });
  return (await res.json()) as { name: string; description: string };
}

export function meta({ loaderData }: Route.MetaArgs) {
  return [{ title: loaderData?.name ?? "Product" }];
}

export default function Product({ loaderData }: Route.ComponentProps) {
  return (
    <article>
      <h1>{loaderData.name}</h1>
      <p>{loaderData.description}</p>
    </article>
  );
}

Choose it when:

  • You want server rendering and good SEO, but prefer loaders and actions over the React Server Components model.
  • You like web standards: Request, Response, FormData and progressive enhancement with <Form>.
  • You want to start as an SPA (ssr: false in react-router.config.ts) and add SSR or pre-rendering later without changing your routes.
  • You are upgrading an existing React Router data-mode or Remix app.

The trade-offs: React Server Components support is still marked unstable in v8, the ecosystem of examples is smaller than Next.js, and you own more of the deployment setup.

When to choose Next.js

Terminal
npx create-next-app@latest my-app

Next.js 16 is the most complete option. The App Router uses React Server Components by default, so components that only render data never ship their JavaScript to the browser. Server Actions handle mutations, the metadata API and file conventions cover SEO basics, and next/image and next/font help with Core Web Vitals.

TSX
// app/products/[id]/page.tsx
import type { Metadata } from "next";

type Product = { name: string; description: string };

async function getProduct(id: string): Promise<Product> {
  const res = await fetch(`https://api.example.com/products/${id}`);
  if (!res.ok) throw new Error("Failed to load product");
  return res.json();
}

export async function generateMetadata({
  params,
}: {
  params: Promise<{ id: string }>;
}): Promise<Metadata> {
  const { id } = await params;
  const product = await getProduct(id);
  return { title: product.name, description: product.description };
}

export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const product = await getProduct(id);
  return (
    <article>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
    </article>
  );
}

Note that params is a Promise in Next.js 15 and later, and synchronous access was removed in 16.

Choose it when:

  • Organic search traffic matters: marketplaces, ecommerce, blogs, landing pages.
  • You want backend code (database queries, auth, webhooks) in the same project.
  • You need mixed rendering per route: static, revalidated in the background, or fully dynamic.
  • Your team benefits from the largest set of examples, libraries and hiring pool.

For Mercury 360, an AI HR platform I worked on, we used Next.js pre-rendering with background revalidation, so pages are served pre-rendered while their content refreshes in the background. That kind of per-route rendering control is the main reason I reach for Next.js on public-facing products.

The trade-offs: more concepts to learn (server vs client components, caching, the network boundary), a heavier mental model when debugging, and some features that work best on Vercel, although self-hosting with next start or Docker is fully supported. If you are weighing hosting, see deploying Next.js: Vercel vs self-hosting with Docker, and for the caching model, Next.js caching explained.

A quick decision checklist

  1. Does any page need to rank in search or render a rich link preview? If yes, rule out a plain SPA for those pages. Use Next.js or React Router framework mode.
  2. Do you want React Server Components today? Next.js. React Router's support is still unstable.
  3. Is the app entirely behind authentication? Vite SPA is the simplest option. React Router framework mode in SPA mode also works and leaves room to grow.
  4. Do you need to host on static storage only, with no server? Vite, or either framework's static/pre-render output, keeping their limits in mind.
  5. Is the team new to React? Start with Vite to learn React itself, then move to a framework when you need what it offers.

Also worth knowing: the React docs list TanStack Start as an up-and-coming framework. It is also built on Vite and is worth evaluating if your team already uses TanStack Router and Query.

Common mistakes when choosing a React framework

  • Picking Next.js for an internal dashboard just because it is popular. You pay the complexity cost and get none of the SEO benefit.
  • Building a public marketing site as a client-only SPA. Then trying to bolt on pre-rendering later.
  • Comparing Vite and Next.js as if they were the same kind of tool. Vite is a build tool. Next.js is a framework with its own bundler. React Router framework mode is a framework that uses Vite.
  • Following outdated tutorials. Look out for react-router-dom imports (removed in v8), middleware.ts in Next.js 16 (now proxy.ts) and Create React App setups.
  • Ignoring hosting until launch. SSR needs a server or a platform adapter. Decide early.

The React team's own guidance on creating a React app is a good neutral reference if you want the official view.

FAQ

Should I use Vite or Next.js for a new React project?

Use Next.js when you need server rendering, React Server Components, SEO for public pages or backend logic in the same project. Use plain Vite for client-only apps behind a login, like dashboards and admin panels, where a static SPA is simpler to build and host.

Is React Router framework mode the same as Remix?

It is the successor to Remix v2 for React apps. The Remix framework features (loaders, actions, SSR, route modules) were merged into React Router, which runs as a Vite plugin in framework mode. Remix 3 is a separate, still pre-release project.

Is Create React App still an option in 2026?

No. Create React App is deprecated, and the React docs now point to frameworks such as Next.js and React Router, or to building from scratch with a build tool like Vite.

Can a Vite React SPA rank well on Google?

It can, but it is harder. Google renders JavaScript, yet content that only appears after client-side fetching is slower to index and other crawlers may not render it. For public, content-heavy pages, server rendering or pre-rendering is the safer choice.

Wrapping up

Match the tool to where your users and crawlers meet the app. Public, content-heavy or full-stack products fit Next.js; apps that want SSR with a web-standards feel fit React Router framework mode; and apps behind a login are often happiest as a Vite SPA. All three are solid in 2026, so choose the one whose trade-offs you are happy to live with.

  • #react
  • #vite
  • #nextjs
  • #react-router
  • #architecture