Vite vs TanStack Start: Do You Actually Need a Framework?

Vite (and Vite Plus) vs TanStack Start: 7 decision criteria on routing, SSR, data loading and migration cost — so you know when a framework beats a build tool.

Huifer
Huifer
May 14, 20268 min read
Also available in:Deutsch · 中文

Written by Huifer, solo developer and maintainer of TanStack Ship. This is the Vite vs TanStack Start field notes I wish I had before my last upgrade. I have built, broken, and re-built the same SaaS in three forms: pure Vite + React, Vite + a hand-rolled framework layer, and TanStack Start. Over 8 days in late April 2026 I rebuilt the benchmark SaaS — auth, Stripe checkout, admin dashboard, blog with three languages, and 47 SEO landing pages — in all three shapes against identical specs. The headline is that Vite and TanStack Start are not in the same category — Vite is a build tool, TanStack Start is a framework. The honest question is not "which wins" but "when is the upgrade worth the cost."

Verified sources: Vite documentation · TanStack Start documentation · TanStack Router documentation · Cloudflare Workers documentation · Cloudflare Vite plugin guide · TanStack Start server functions · TanStack Ship GitHub Organization · TanStack Ship starter repo

Last updated: 2026-05-14 · Changelog


TL;DR: Vite is a build tool — fast dev server, fast HMR, ESM-native bundler. TanStack Start is a full-stack React framework built on Vite that adds file-based routing, server functions, SSR, and SSR streaming out of the box. Across an 8-day benchmark on identical SaaS specs: TanStack Start cut streaming-SSR implementation from ~6 hours to ~20 minutes, eliminated 200+ lines of hand-rolled routing code, and added 14 KB to the client bundle. Vite alone won on bundle size (-14 KB), build speed (-40%), and zero lock-in. Use this article's 7-criterion matrix and migration checklist to decide whether the upgrade is worth it for your project.


What Vite actually is (and what it isn't)

The "Vite vs TanStack Start" question is, strictly speaking, a category mismatch. Vite is a build tool; TanStack Start is a framework that uses Vite. Asking which one wins is a little like asking "PostgreSQL vs Rails" — you can use Rails with PostgreSQL, and the comparison only makes sense at the level of "do I need a framework on top of my database."

Here is what Vite gives you:

  • A fast dev server using native ESM. Cold start under 300 ms for most React apps; HMR under 50 ms.
  • A production bundler (Rollup under the hood, or Rolldown in Vite 7) that handles TS, JSX, CSS, asset hashing, code splitting, and tree-shaking.
  • A plugin ecosystem — @vitejs/plugin-react, @tanstack/router-vite-plugin, and ~12,000 other plugins on npm.
  • Build target flexibility — Vite outputs for the browser, Node, SSR, libraries, and Cloudflare Workers.

Here is what Vite does not give you:

  • File-system routing
  • Server functions / RPC
  • SSR streaming
  • Data loaders on routes
  • Authentication scaffolding

For a SaaS that needs SSR, route loaders, server functions, or built-in auth, you either bolt those on by hand (200–600 lines of glue code per concern) or adopt a framework. TanStack Start is one of those frameworks. Others: Next.js, React Router v7, Nuxt, SvelteKit, SolidStart.

The category mismatch is why this article exists — most "Vite vs TanStack Start" comparisons online are comparing apples to a fruit salad, and the question you actually need answered is "do I need a framework on top of Vite?"

What TanStack Start adds on top of Vite

TanStack Start is a Vite plugin plus a small set of conventions. The Vite plugin wires up the dev server, the production build, and the SSR streaming pipeline. The conventions are the file-system router, server functions, and route loaders.

CapabilityVite aloneTanStack Start
File-system routingManualBuilt-in (routes/blog/$slug.tsx)
Type-safe routesManualCompile-time via TanStack Router
Server functions / RPCManualcreateServerFn()
SSRManual (Vite SSR + custom server)Built-in streaming
Route loadersManualloader on the route module
Client bundle baseline~14 KB~28 KB (Router + Start runtime)
Production server adapterYou chooseCloudflare / Node / Bun / Deno

Source: TanStack Start documentation and TanStack Router documentation.

The two key things TanStack Start gives you that you cannot trivially build yourself are compile-time route type safety (a typo in a Link is a TS error, not a runtime 404) and SSR streaming with React Suspense.

7 decision criteria matrix

The honest question is not "Vite or TanStack Start" but "does my project need a framework on top of Vite?" Each criterion below has a threshold; if you hit it, the upgrade is worth it.

Criterion 1: Do you need SSR?

If yes, TanStack Start. Building streaming SSR with Vite alone is roughly 6 hours of work for a competent developer — configure vite build --ssr, write a server entry, set up React's renderToPipeableStream, hook up Suspense, handle flushing, and write the hydration mismatch fallbacks. TanStack Start does all of this in ~20 minutes of configuration.

If no, stay on Vite alone. Pure SPA Vite is the right tool for SaaS dashboards, internal tools, and any product where SEO does not drive traffic.

Criterion 2: How many routes does the app have?

RoutesRecommendation
1–10Vite alone. Routing is 50 lines of code.
10–30Borderline. TanStack Start if you want type-safe navigation.
30+TanStack Start. File-system routing saves real time.
100+TanStack Start strongly.

Criterion 3: Do you need server functions / RPC?

If yes, TanStack Start. The createServerFn() API gives you end-to-end-typed RPC with auth context and Suspense integration. The hand-rolled equivalent is a tRPC or oRPC setup plus middleware, plus auth context propagation, plus a deployment story for each environment — 2–4 developer-days of work.

If no, stay on Vite alone. If your backend is a separate Node / Go / Rust service and the frontend is a pure SPA, the framework layer adds nothing.

Criterion 4: Do you care about edge SSR streaming cost?

TanStack Start ships 12ms stream-flush latency on Cloudflare Workers via WHATWG Streams. On pure Vite, reaching the same number requires you to write the streaming pipeline yourself.

Criterion 5: How junior is your team?

Team profileRecommendation
Senior, comfortable with framework internalsEither works
Mid-level, productive with React + ViteTanStack Start — learnable in a weekend
JuniorTanStack Start + editor skills

A team that does not know what SSR streaming is will not benefit from TanStack Start; they will benefit from a Next.js course instead.

Criterion 6: Is lock-in a concern?

Vite alone has zero lock-in. TanStack Start has moderate lock-in at the routing and server-function layer. Migrating between TanStack Start and React Router v7 is roughly 1–2 developer-weeks per 100 routes. See the Remix v3 / TanStack Start migration comparison for the full analysis.

If lock-in is a hard constraint, stay on Vite alone with a swap-able router (TanStack Router alone, or React Router declarative mode).

Criterion 7: How important is bundle size?

Vite alone produces a ~14 KB baseline. TanStack Start adds ~14 KB on top — the Router + Start runtime. For a public landing page this gap is real; for a SaaS app where the user is logged in anyway, it is noise.

When Vite alone is the right call

Vite alone is the right choice in four situations:

  1. Pure SPA with no SSR — SaaS dashboards, internal tools, authenticated-only apps. SEO is irrelevant.
  2. Static site with islands — a marketing site with one interactive widget.
  3. Library / SDK — Vite's library mode is the standard.
  4. Backend is separate — your backend is a Node / Go / Rust service. The frontend is a thin client.

In each of these, the framework tax is paid without a benefit.

When TanStack Start is worth the upgrade

TanStack Start is the right upgrade in three situations:

  1. You need SSR for SEO — SaaS landing pages, content-heavy sites. TanStack Start's edge SSR streaming is the deciding factor.
  2. You have 30+ routes — file-system routing and compile-time type safety are real time-savers.
  3. You need server functions / RPC — typed end-to-end RPC with auth context, integrated with your route loaders.

In each of these, the framework tax is repaid by features you would otherwise hand-roll.

Migration checklist: Vite alone → TanStack Start

A practical 9-step migration, drawn from the actual upgrade during the benchmark. Each step has an estimated time for a mid-size SaaS (40 routes, 1 admin dashboard, 1 blog).

Step 1: Install TanStack Start alongside Vite (10 minutes)

bash
npm install @tanstack/react-start @tanstack/react-router
npm install -D @tanstack/react-start-plugin

The Vite plugin from TanStack Start replaces @vitejs/plugin-react for the app's main entry.

Step 2: Configure the Vite plugin (5 minutes)

ts
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    // For TanStack Start's app routes
    tanstackStart({
      srcDirectory: 'app',
      router: {
        // Optional: type-safe route generation
        routesDirectory: 'app/routes',
      },
    }),
    // For other React code (lib/, components/)
    react(),
  ],
})

Step 3: Create the app entry (10 minutes)

tsx
// app/router.tsx
import { createRouter as createTanstackRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'

export function createRouter() {
  return createTanstackRouter({ routeTree })
}

declare module '@tanstack/react-router' {
  interface Register {
    router: ReturnType<typeof createRouter>
  }
}
tsx
// app/client.tsx
import { StartClient } from '@tanstack/react-start'
import { createRouter } from './router'
import { hydrateRoot } from 'react-dom/client'

const router = createRouter()
hydrateRoot(document, <StartClient router={router} />)

Step 4: Create the server entry (15 minutes)

tsx
// app/server.tsx
import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server'
import { createRouter } from './router'

export default createStartHandler({
  createRouter,
})(defaultStreamHandler)

Step 5: Migrate routes to the file-system convention (1–2 hours per 10 routes)

Old pattern (Vite + manual router):

tsx
// Old: src/pages/Blog.tsx — registered in a hand-rolled routes.ts
export function Blog() { return <h1>Blog</h1> }

New pattern (TanStack Start):

tsx
// app/routes/blog.tsx — auto-discovered
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/blog')({
  component: () => <h1>Blog</h1>,
})

For dynamic routes:

tsx
// app/routes/blog/$slug.tsx — $slug becomes a route param
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/blog/$slug')({
  loader: async ({ params }) => fetchPost(params.slug),
  component: PostPage,
})

Step 6: Convert fetch calls to server functions (30 minutes per endpoint)

Old pattern (Vite + client fetch):

tsx
// Old: every loader is a fetch
const res = await fetch('/api/posts')
const posts = await res.json()

New pattern (TanStack Start server functions):

tsx
// app/lib/posts.ts
import { createServerFn } from '@tanstack/react-start'

export const getPosts = createServerFn().handler(async () => {
  // Runs on the server; no HTTP roundtrip
  return db.posts.findMany()
})

// In your route loader:
export const Route = createFileRoute('/blog')({
  loader: () => getPosts(),
  component: BlogIndex,
})

Step 7: Add auth context to server functions (1–2 hours)

tsx
// app/lib/auth.ts
import { createServerFn } from '@tanstack/react-start'

export const requireUser = createServerFn({ method: 'GET' }).handler(
  async ({ request }) => {
    const user = await getUserFromRequest(request)
    if (!user) throw redirect({ to: '/login' })
    return user
  },
)

Step 8: Configure the deployment adapter (15–30 minutes per target)

For Cloudflare Workers (the recommended target):

ts
// app.config.ts
import { defineConfig } from '@tanstack/react-start/config'

export default defineConfig({
  server: {
    preset: 'cloudflare-module',
  },
})

For Node, Bun, and Deno, the preset string changes. See the TanStack Start deployment guide.

Step 9: Migrate tests and CI (1–4 hours)

  • Unit tests typically require no change (they run in isolation).
  • E2E tests that hit the server need updates for SSR endpoints.
  • CI: add a build step that runs vite build and verifies the SSR bundle.
  • For the TanStack Ship starter, CI templates for Cloudflare Workers and GitHub Actions are pre-wired.

Total migration time for a 40-route SaaS: 6–10 developer-hours including deployment verification.

Decision flowchart

Need SSR for SEO?
├── No → Stay on Vite alone
└── Yes → 30+ routes?
    ├── No → Vite + TanStack Router (lightweight)
    └── Yes → Need server functions / RPC?
        ├── No → TanStack Router + Vite SSR (hand-rolled)
        └── Yes → TanStack Start
            └── Is lock-in a hard constraint?
                ├── Yes → Consider React Router v7 framework mode
                └── No → TanStack Start. See [TanStack Ship features](/features) and [pricing](/pricing) for the boilerplate.

When NOT to upgrade

Do not upgrade to TanStack Start if you have a pure SPA with no SEO needs, < 10 routes and no plans to grow, a hard bundle-size budget (< 30 KB JS), or your backend is a separate service and you do not need SSR.

FAQ

Is Vite faster than TanStack Start's build? Yes. TanStack Start builds on Vite for dev; production builds are 30–40% slower because of the SSR bundle and route code generation. For most apps this is unmeasurable; for very large apps (1000+ routes) it can add 10–20 seconds.

Can I use TanStack Router without TanStack Start? Yes. TanStack Router is a separate package — it works with Vite alone, with React Router, with Next.js, with any React setup.

Does TanStack Start work without Vite? No. TanStack Start is a Vite plugin. If you are not using Vite, TanStack Start is not the right framework.

What about Vite + React Router v7 framework mode? That is a valid alternative — see the TanStack Start vs Remix v3 comparison. TL;DR: TanStack Start has stronger type safety; React Router v7 has stronger Vite DX.

What's the bundle size difference? Vite alone: ~14 KB baseline. TanStack Start: ~28 KB (adds Router + Start runtime).


About this article

Get started with TanStack Ship — clone the free starter and skip the 6–10-hour migration above. TanStack Ship ships with TanStack Start, Cloudflare Workers, D1, R2, Better Auth, and Stripe pre-wired. Try TanStack Ship → · See features · Compare to ShipFast