Skip to content

@tank/nextjs-to-tanstack

1.0.0

Migrate Next.js applications to TanStack Start — escape Vercel lock-in with a client-first, type-safe, deploy-anywhere React framework. Covers routing, data fetching, components, auth, deployment, and migration strategy.


name: "nextjs-to-tanstack" description: | Migrate Next.js applications to TanStack Start — escape Vercel lock-in with a client-first, type-safe, deploy-anywhere React framework. Covers the full migration lifecycle: routing conversion (App Router and Pages Router), data fetching (RSC/getServerSideProps to loaders and createServerFn), component migration (Link, Image, Head, fonts, navigation hooks), auth and middleware patterns, deployment to any platform via Nitro (Cloudflare, AWS, Netlify, Bun, Deno, self-hosted), and migration strategy (brute-force, strangler fig, AI-assisted). Synthesizes TanStack Start official docs, Inngest migration case study (Jan 2026), BeyondIT benchmarks, TkDodo patterns, and production community examples.

Trigger phrases: "next.js to tanstack", "nextjs to tanstack", "migrate from nextjs", "migrate from next.js", "tanstack start", "tanstack start migration", "escape vercel", "leave nextjs", "leave next.js", "nextjs alternative", "replace nextjs", "move off nextjs", "ditch nextjs", "nextjs lock-in", "vercel lock-in", "nextjs to tanstack start", "convert nextjs", "tanstack start conversion", "next.js migration", "nextjs migration"

Next.js to TanStack Start Migration

Core Philosophy

  • Explicit over magic — TanStack Start has no use client/use server directives, no implicit RSC boundaries, no opaque caching layers. Server code is explicitly declared with createServerFn() and route loader functions.
  • Deploy anywhere — Nitro abstracts all platform differences. Same codebase deploys to Vercel, Cloudflare Workers, AWS Lambda, Bun, Deno, or a $20/mo VPS. No vendor lock-in.
  • Type safety end-to-end — Route params, loader data, search params, and server function return types are all inferred by TypeScript. Invalid routes are compile errors.
  • Client-first, server-capable — All components are standard React. Server capabilities are added explicitly, not assumed by default. The mental model is a React SPA that can optionally fetch data on the server.

Quick-Start: What Are You Migrating?

Starting PointKey ChangesPrimary Reference
App Router (RSC)Remove directives, RSC → loaders + createServerFnreferences/data-and-server-functions.md
App Router (routing)[slug]$slug, layout.tsx → __root.tsxreferences/routing-migration.md
Pages RoutergetServerSideProps → loader, _app → __rootreferences/routing-migration.md
Server Actions'use server'createServerFn()references/data-and-server-functions.md
next/link, next/imagehrefto, Image → @unpic/reactreferences/component-migration.md
middleware.tsEdge middleware → beforeLoad + createMiddlewarereferences/auth-and-middleware.md
next.config.js→ vite.config.ts + Nitro presetsreferences/deployment-and-config.md
Auth (NextAuth, etc.)Session/Better Auth patterns for TanStackreferences/auth-and-middleware.md
DeploymentVercel-only → deploy anywherereferences/deployment-and-config.md

Concept Mapping

Next.jsTanStack StartNotes
app/layout.tsxroutes/__root.tsxcreateRootRoute() + <Outlet />
app/page.tsxroutes/index.tsxcreateFileRoute('/')
app/[slug]/page.tsxroutes/$slug.tsxDynamic: [slug]$slug
app/[...slug]/page.tsxroutes/$.tsxCatch-all via _splat param
getServerSidePropsRoute loaderExplicit server boundary
Server Actions ('use server')createServerFn()Explicit, typed, validated
next/link (href)<Link to="...">Fully type-safe
next/image@unpic/react or <img>No built-in optimization server
metadata exportRoute head() functionMerges up the route tree
middleware.tsbeforeLoad / createMiddlewarePer-route, not edge-global
next.config.jsvite.config.tsVite + Nitro plugins
NEXT_PUBLIC_ env varsVITE_ env varsVite convention
loading.tsxpendingComponentRoute option
error.tsxerrorComponentRoute option
not-found.tsxnotFoundComponentRoute option
useRouter().push()useNavigate()Type-safe navigation
useSearchParams()Route.useSearch()Requires validateSearch
useParams()Route.useParams()Fully typed

Migration Approach Decision Tree

SignalApproachReference
< 30 routes, small teamBrute-force (convert all at once)references/migration-strategy.md
30+ routes, mission-criticalStrangler fig (incremental via proxy)references/migration-strategy.md
Shared component libraryMonorepo migrationreferences/migration-strategy.md
Many similar routesAI-assisted (establish patterns, AI converts)references/migration-strategy.md

Common Gotchas

GotchaImpactFix
No RSC — everything is client-capableRSC patterns breakUse loaders + createServerFn
Dev mode ≠ productionBehaviors differAlways vite build && vite preview
CSS needs ?url suffix in rootBroken SSR stylesimport css from './app.css?url'
routeTree.gen.ts errors before first runExpectedRun vite dev once to generate
ThemeProvider FOUCFlash of unstyled contentUse ScriptOnce for theme script
Auth libs need explicit baseURLAuth calls failSet baseURL in auth client
Huge migration PRsCan't code reviewPlan for UAT-based validation
No Parallel/Intercepting RoutesLayout patterns breakConditional rendering or search params

Performance Expectations

MetricNext.js (before)TanStack Start (after)Source
Dev server startup10-12s2-3sInngest
Client bundle sizebaseline30-35% smallerBeyondIT
Build time (CI)baseline7x fasterBeyondIT
Dev memory usage9-10 GBStandard NodeBeyondIT

Features With No Direct Equivalent

Next.js FeatureTanStack Start Status
next/og (OG image gen)Use Satori directly or external service
Parallel Routes (@slot)Conditional rendering
Intercepting Routes ((.))Not available
ISR (revalidate: 60)Basic ISR exists, not as mature
Edge RuntimeCloudflare Workers via Vite plugin
use cache directiveTanStack Query for client caching
Image optimization serverExternal CDN (Cloudinary, Imgix)

Workflow

  1. Assess scope — count routes, identify RSC-heavy pages, check deployment needs.
  2. Choose migration approach — brute-force, strangler fig, or monorepo. See references/migration-strategy.md.
  3. Set up TanStack Start project — vite.config.ts, router.tsx, __root.tsx. See references/deployment-and-config.md.
  4. Convert routes — file naming, loaders, components. See references/routing-migration.md.
  5. Migrate data fetching — loaders, server functions, TanStack Query. See references/data-and-server-functions.md.
  6. Migrate UI components — Link, Image, Head, navigation hooks. See references/component-migration.md.
  7. Migrate auth — middleware, session, guards. See references/auth-and-middleware.md.
  8. Configure deployment — Nitro preset, env vars. See references/deployment-and-config.md.
  9. Learn TanStack patterns — type-safe nav, search params, preloading. See references/tanstack-start-patterns.md.
  10. Verify — build, preview, UAT, performance comparison.

Reference Files

FileContents
references/routing-migration.mdFile routing conversion, dynamic params, layouts, __root.tsx, route tree, API routes
references/data-and-server-functions.mdLoaders, createServerFn, mutations, TanStack Query integration, streaming/deferred
references/component-migration.mdLink, Image, Head/meta, fonts, navigation hooks, error/loading/notFound, search params
references/deployment-and-config.mdvite.config.ts, Nitro presets, env vars, platform-specific configs, static export
references/auth-and-middleware.mdbeforeLoad, createMiddleware, session auth, Better Auth, context inheritance, guards
references/migration-strategy.mdStep-by-step procedures, brute-force vs strangler fig, AI-assisted migration, gotchas, rollback
references/tanstack-start-patterns.mdType-safe navigation, search params, preloading, devtools, SSR+Query, router context

Command Palette

Search skills, docs, and navigate Tank