TanStack Ecosystem: Complete Guide to Router, Query & Start in 2026

Ein umfassender Guide zum TanStack-Ökosystem 2026 — Router, Query und Start. Wie sie zusammenarbeiten, wann man welches Tool einsetzt und was in der Praxis wirklich funktioniert.

Huifer
Huifer
20. Juni 202612 min read
Auch verfügbar auf:English

Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Ich habe Ende 2024 die erste TanStack-basierte Produktiv-App auf Cloudflare Workers deployed und seitdem zwölf weitere auf demselben Stack. Das TanStack-Ökosystem — Router, Query und Start — ist der einzige React-Stack, dem ich als Einzelperson vertraue, wenn es darum geht, Arbeit ohne Runtime-Überraschungen vor zahlende Kunden zu bringen. Dieser Guide ist das Feldhandbuch, das ich mir gewünscht hätte, als ich angefangen habe: wann sich jedes Framework lohnt, wann man es weglässt und welche Patterns in der Praxis wirklich funktionieren.

Verifizierte Quellen: TanStack Router Documentation · TanStack Query Documentation · TanStack Start Documentation · TanStack GitHub Organization · Cloudflare Workers Documentation · TanStack Ship Features · TanStack Ship Blog Index · TanStack Router vs React Router Letzte Aktualisierung: 2026-06-20 · Changelog


TL;DR: Das TanStack-Ökosystem im Jahr 2026 besteht aus drei Bibliotheken, die jeweils ein eigenes Problem lösen und sauber zusammenarbeiten. TanStack Router ist ein vollständig typsicherer Client-seitiger Router mit Suchparametern, Loadern und Code-Splitting auf erstklassigem Niveau. TanStack Query ist ein Server-State-Cache, der Fetching, Caching und Synchronisierung übernimmt, damit Sie es nicht selbst bauen müssen. TanStack Start ist ein Full-Stack-Framework, das auf Router aufbaut und Server Functions, SSR und Deployment-Adapter hinzufügt. Für Solo-SaaS-Entwickler im Jahr 2026 ist dies der einzige React-Stack, der Typsicherheit End-to-End, Edge-Deployment und kein separates API-Backend bietet.


Warum es das TanStack-Ökosystem gibt

Im Jahr 2026 gibt es viele React-Stacks. Next.js, Remix, Astro, Redwood — jeder setzt auf eine andere Wette hinsichtlich der Grenze zwischen Server und Client. Das TanStack-Ökosystem setzt auf etwas anderes: Client-Router, Client-seitiger Server-State-Cache und Server-Runtime als drei unabhängige, composable Bausteine zu behandeln und den Entwicklern zu überlassen, sie selbst zusammenzustecken.

Laut der TanStack Router Dokumentation wurde der Router gebaut, um vollständig typsicher zu sein — der Route-Tree ist ein Typ, mit dem der Compiler arbeitet, sodass useParams(), useSearch() und Link alle zur Compile-Zeit geprüft werden. Laut der TanStack Query Dokumentation wurde die Query-Bibliothek gebaut, weil „Data Fetching schwierig ist und die meisten Apps es falsch machen" — sie ist die meist-heruntergeladene Data-Fetching-Bibliothek für React. Laut der TanStack Start Dokumentation komponiert Start Router und Query mit Server Functions und einem Deployment-Adapter.

Der Grund, warum das 2026 relevant ist: Die Alternativen zwingen Sie zu einer Wahl zwischen Typsicherheit, Edge-Deployment und einem sauberen Mental Model. Next.js bietet Edge-Deployment und SSR, aber der Router ist nicht vollständig typsicher. Remix wurde in React Router überführt. Astro eignet sich hervorragend für Content-Sites, aber nicht für stateful SaaS-Apps. Der TanStack-Stack ist der einzige, den ich 2026 in Produktion gebracht habe und der mir alle drei bietet. Für einen breiteren Überblick, wo dies hineinpasst, besuchen Sie die TanStack Ship Features-Seite und den TanStack Ship Comparison Hub.

Was „das Ökosystem" tatsächlich bedeutet

TanStack ist eine Bibliotheksfamilie, die sich einen Autor, eine Philosophie strenger Typsicherheit und ein Deployment-Ziel teilt, aber jede Bibliothek kann unabhängig verwendet werden. Sie können Query ohne Router einsetzen. Sie können Router ohne Start einsetzen. Sie können Start verwenden, ohne jemals Query zu berühren. Diese Composability ist das Feature, kein Nebeneffekt.

In Produktion verwende ich Router für den Route-Tree und Code-Splitting, Query für jeden Server-State-Read auf dem Client und Start für die Server Functions, den SSR-Entry-Point und den Cloudflare Workers-Adapter. Ich verwende die Router-Loader-API nicht für Data Fetching — dafür nutze ich Query, weil die Cache-Invalidierung genau das ist, was ich brauche. Die Router-Loader-API verwende ich für Route-Level-Guards. Die Grenze ist einfach: Der Server ist für Dinge, die nur der Server erledigen kann (in die Datenbank schreiben, Stripe aufrufen, ein JWT signieren), und der Client ist für alles andere.

TanStack Router — der typsichere Route-Tree

TanStack Router ist das opinionierteste Stück des Ökosystems. Es ersetzt React Router, Next.js App Router und die verschiedenen file-basierten Router durch einen Code-First Route-Tree, den der Compiler versteht. Der Typ dieses Trees ist der Typ der gesamten App, und jede Link-Komponente, jeder useNavigate-Hook und jeder useParams-Hook wird dagegen geprüft. Wenn ein Parameter nicht existiert, schlägt der Compiler fehl. Wenn ein Suchparameter fehlt, teilt Ihnen der Typ das mit.

Der größte Produktivitätsgewinn ist die Suchparameter-Validierung. In den meisten React-Stacks gibt useSearchParams() URLSearchParams zurück, und Sie müssen die Daten selbst parsen, validieren und ihnen vertrauen. In TanStack Router sind Suchparameter ein Zod-Schema:

typescript
// app/routes/products.tsx
import { z } from 'zod'
import { createRoute, useSearch } from '@tanstack/react-router'

const productSearchSchema = z.object({
  category: z.enum(['all', 'electronics', 'apparel']).default('all'),
  page: z.number().int().positive().default(1),
  sort: z.enum(['price-asc', 'price-desc', 'newest']).default('newest'),
})

export const Route = createRoute({
  getParentRoute: () => rootRoute,
  path: '/products',
  validateSearch: productSearchSchema,
  component: ProductsPage,
})

function ProductsPage() {
  const { category, page, sort } = useSearch({ from: Route.id })
  // category, page, sort sind typisiert — keine Casts, kein `as`
}

Das klingt klein, bis man es einsetzt. Ich hatte 2024 eine Klasse von Bugs, die es nicht mehr gibt: ein Suchparameter, der nicht dem entsprach, was der Consumer erwartete. Das Schema ist der Vertrag. Der Compiler setzt ihn durch.

File-basierte vs. Code-basierte Routes

TanStack Router unterstützt beides. Der file-basierte Router verwendet @tanstack/router-plugin, um den Route-Tree aus einem routes/-Verzeichnis zu generieren. Der code-basierte Router verwendet einen expliziten createRoute-Aufruf pro Route. Ich verwende file-basiert bei Produktiv-Apps mit mehr als 20 Routes und code-basiert bei kleineren Apps, bei denen der Route-Tree das Design-Dokument ist.

Was Router nicht löst

Router ist ein Client-Router. Er fetched keine Daten, rendert nicht auf dem Server und kennt Ihre Datenbank nicht. Die Loader-API ist ein Pre-Routing-Hook, keine Data-Fetching-Schicht. Wenn Sie Daten laden müssen, verwenden Sie einen Loader (für Daten, die die Route-Transition blockieren sollten) oder Query (für alles andere). Die TanStack Query Dokumentation argumentiert dies im Detail.

TanStack Query — der Server-State-Cache, den Sie nicht selbst schreiben müssen

TanStack Query ist die meist-heruntergeladene Data-Fetching-Bibliothek für React. Sie ist keine Server-State-Bibliothek im Redux-Sinne — sie besitzt nicht die Source of Truth. Sie ist ein Cache des Server-States, mit Regeln dafür, wann revalidieren, wann invalidieren und wann im Hintergrund neu fetchen. Der Server ist die Source of Truth. Der Cache ist eine Performance-Optimierung, die zusätzlich eine saubere API bietet.

Die meisten React-Apps in 2026 fetchen Daten immer noch von Hand. Ein useEffect mit einem fetch-Aufruf, ein useState für das Ergebnis, ein useState für den Fehler, ein useState für die Loading-Flag. Drei Hooks pro Request. Mit Query sind es ein Hook:

typescript
// app/hooks/useProducts.ts
import { useQuery } from '@tanstack/react-query'

export function useProducts(category: string, page: number) {
  return useQuery({
    queryKey: ['products', category, page],
    queryFn: () =>
      fetch(`/api/products?category=${category}&page=${page}`).then(r => r.json()),
    staleTime: 30_000,
    gcTime: 5 * 60_000,
    refetchOnWindowFocus: true,
  })
}

Der Gewinn liegt nicht in der Syntax. Der Gewinn ist, dass derselbe Hook Loading, Error, Success, Revalidation und Cache-Invalidation behandelt. Wenn ich queryClient.invalidateQueries({ queryKey: ['products'] }) von irgendwo in der App aufrufe, fetched jede Komponente, die useProducts verwendet, erneut. Wenn zwei Komponenten denselben queryKey verwenden, teilen sie sich den Cache. Wenn der User innerhalb der stale time wegnavigiert und zurückkommt, passiert kein Netzwerk-Call.

Mutations und Optimistic Updates

Query behandelt Writes über useMutation, und die onMutate/onError/onSettled-Callbacks bieten das Optimistic-Update-Pattern mit Rollback gratis. Das Pattern: onMutate schreibt den optimistic Value in den Cache und liefert einen Snapshot zurück; die Server-Funktion läuft; onSuccess invalidiert die Query; onError rolled auf den Snapshot zurück. Das ist das richtige Pattern zum Bearbeiten eines Datensatzes, den der User sehen kann. Zum Erstellen eines neuen Datensatzes, dessen Response der neue Datensatz ist, verwenden Sie setQueryData mit der Response.

Was Query nicht löst

Query fetched keine Daten — es verwaltet den Cache um den Fetch herum. In einer TanStack Start App ist der natürliche Weg für den eigentlichen HTTP-Call eine Server-Funktion (weiter unten behandelt). Query macht auch kein Server-seitiges Data Fetching. Wenn Sie auf dem Server fetchen und die Daten mit dem HTML mitschicken wollen, brauchen Sie eine Server-Rendering-Story. Dafür gibt es Start.

TanStack Start — das Full-Stack-Framework

TanStack Start ist das jüngste der drei und das am schnellsten sich entwickelnde. Es ist ein Full-Stack-Framework, das Router und Query mit einer Server-Functions-API, einer SSR-Pipeline und einem Deployment-Adapter zusammensetzt. Routes sind immer noch Router-Routes, aber jede Route kann eine Server-Funktion haben, die auf dem Server läuft, und das Framework kümmert sich um den Build, den Bundler und das Deployment.

Laut der TanStack Start Dokumentation ist die Server-Functions-API das zentrale Feature. Eine Server-Funktion sieht im Code wie eine normale Funktion aus, läuft aber zum Zeitpunkt des Aufrufs auf dem Server:

typescript
// app/server/products.ts
import { createServerFn } from '@tanstack/start/server'
import { z } from 'zod'
import { db } from '~/lib/db'
import { products } from '~/lib/schema'

export const fetchProducts = createServerFn({ method: 'GET' })
  .validator(z.object({ category: z.string(), page: z.number() }))
  .handler(async ({ data }) => {
    return db.select().from(products)
      .where(eq(products.category, data.category))
      .limit(20).offset((data.page - 1) * 20)
  })

Der client-seitige Aufruf:

typescript
// app/routes/products.tsx
import { useQuery } from '@tanstack/react-query'
import { fetchProducts } from '~/server/products'

const { data, isLoading, error } = useQuery({
  queryKey: ['products', category, page],
  queryFn: () => fetchProducts({ data: { category, page } }),
})

Die Grenze ist für den Entwickler unsichtbar. Die Funktion ist eine Server-Funktion, also läuft sie auf dem Server. Die Query läuft auf dem Client. Die Verkabelung übernimmt das Framework.

Deployment-Adapter

Start wird mit einem Vite-Plugin und einem Satz Deployment-Adapter ausgeliefert. Der Cloudflare Workers-Adapter ist der, den ich verwende — er erzeugt ein Worker-Bundle, verbindet die KV/D1/R2-Bindings und deployed über Wrangler. Laut der Cloudflare Workers Dokumentation zielt der Adapter direkt auf die Workers Runtime, was bedeutet: keine Node.js-Kompatibilitätsschicht, keine Cold-Start-Strafe und keine Überraschungen bei der API-Surface. Die Node.js-, Bun-, Deno- und AWS-Lambda-Adapter existieren, aber ich habe noch nichts damit deployed.

Was Start (noch) nicht löst

Start ist ein junges Framework. Die Plugin-Pipeline wird noch geschliffen, der file-basierte Router-Generator hat raue Kanten, und das Ökosystem an Integrationen ist dünner als bei Next.js. Wenn Sie eine Content-Site mit 50 statischen Seiten und einem Kontaktformular bauen, ist Astro die richtige Antwort. Wenn Sie eine stateful SaaS-App mit Datenbank, Auth und Payments bauen, ist Start für mich 2026 die richtige Antwort — aber das Framework ist nicht so poliert wie Next.js.

Es gibt auch eine Mental-Model-Kosten. Starts Server Functions sind RPC-Style: Der Client importiert eine Funktion, die Funktion läuft auf dem Server, das Ergebnis wird serialisiert. Der Vorteil: kein separates API-Service zum Deployen. Der Nachteil: Sie haben keine öffentliche REST- oder GraphQL-Surface — wenn Sie eine öffentliche API für Drittanbieter-Konsumenten brauchen, müssen Sie diese separat schreiben.

Wie die drei in einer echten App zusammenspielen

Die Gestalt einer produktiven TanStack-App, in der Reihenfolge des Datenflusses:

  1. Die Route wird in Router definiert. Die Route hat einen Pfad, eine Komponente, ein Suchparameter-Schema und einen optionalen Loader.
  2. Die Komponente verwendet Query, um Server-State zu lesen. Die queryFn ruft eine Server-Funktion auf.
  3. Die Server-Funktion läuft auf dem Server, spricht mit der Datenbank und liefert das Ergebnis zurück.
  4. Das Ergebnis wird serialisiert, von Query gecacht und von der Komponente gerendert.
  5. Die Mutation geht andersherum: Ein Button-Klick ruft eine Server-Funktion auf, die Server-Funktion schreibt in die Datenbank, der Cache wird invalidiert, die Komponenten werden neu gerendert.

Die Variation steckt in den Server-Funktionen, der Datenbank und der Auth-Schicht. Ein repräsentatives Produktiv-Pattern aus der TanStack Ship Codebase — eine Server-Funktion, die einen Stripe-Checkout abwickelt:

typescript
// app/server/billing.ts
import { createServerFn } from '@tanstack/start/server'
import { z } from 'zod'
import { stripe } from '~/lib/stripe'
import { db } from '~/lib/db'
import { subscriptions, users } from '~/lib/schema'
import { eq } from 'drizzle-orm'

export const createCheckoutSession = createServerFn({ method: 'POST' })
  .validator(z.object({ priceId: z.string(), customerId: z.string() }))
  .handler(async ({ data, context }) => {
    const user = await db.select().from(users)
      .where(eq(users.stripeCustomerId, data.customerId))
      .limit(1)
    if (!user[0]) throw new Error('User not found')

    const session = await stripe.checkout.sessions.create({
      customer: data.customerId,
      mode: 'subscription',
      line_items: [{ price: data.priceId, quantity: 1 }],
      success_url: `${context.env.APP_URL}/billing/success`,
      cancel_url: `${context.env.APP_URL}/billing/cancel`,
    })

    await db.insert(subscriptions).values({
      userId: user[0].id,
      sessionId: session.id,
      priceId: data.priceId,
      status: 'pending',
    })

    return { url: session.url }
  })

Die Server-Funktion ist End-to-End typisiert. Der Validator ist ein Zod-Schema. Der Handler hat Zugriff auf den Request-Kontext. Der Return-Typ wird inferiert. Die Client-Seite ruft sie genauso auf wie eine lokale Funktion.

Häufige Fehler und wie Sie sie vermeiden

Der erste Fehler: Router's Loader für Data Fetching verwenden. Der Loader läuft bei jeder Route-Transition, blockiert die Navigation und hat keine Cache-Invalidation-Story. Verwenden Sie ihn für Route-Level-Guards. Verwenden Sie Query für Daten.

Der zweite Fehler: Query als Server-State-Bibliothek im Redux-Sinn behandeln. Query ist ein Cache, keine Source of Truth. Das Cache-Update ist der optimistic Schritt, der Server-Write ist die Source of Truth, und die Invalidation ist die Reconciliation.

Der dritte Fehler: Server Functions für Dinge verwenden, die auf den Client gehören. Server Functions sind für Dinge, die nur der Server erledigen kann.

Der vierte Fehler: Server-Funktions-Eingaben nicht validieren. Der Validator ist der Vertrag. Wenn Sie nicht validieren, vertraut die Server-Funktion dem Client — und der Client ist feindlich. Verwenden Sie Zod.

Der fünfte Fehler: Start ohne Test des Deployment-Adapters deployen. Der Cloudflare-Adapter hat seine eigenen Fallstricke bei Bindings, Env-Vars und dem Workers-Modulformat. Testen Sie den Deployment-Pfad am ersten Tag, nicht am Launch-Tag. Für ein durchgearbeitetes Beispiel besuchen Sie die TanStack Ship Features-Seite.

Grenzen dieses Guides

Dieser Guide ist auf einen einzelnen Entwickler begrenzt, der eine stateful SaaS-App auf Cloudflare Workers deployed. Die Zahlen, die ich habe, stammen aus echten Produktiv-Apps bei 50–500 Req/s. Ich habe Router nicht bei 10.000 gleichzeitigen Navigationen, Query nicht bei 10.000 gecachten Einträgen und Start nicht bei 10.000 Req/s benchmarkt. Bei höherer Skalierung sehen die Antworten anders aus.

Ich habe auch nicht gegen Non-React-Frameworks verglichen. Rails, Phoenix, SvelteKit und SolidStart sind alle im Gespräch. Das TanStack-Ökosystem ist React-only, und das ist eine Einschränkung.

Wie es weitergeht

Wenn Sie ein neues Projekt starten, lautet die Antwort 2026: Router + Query + Start auf Cloudflare Workers. Die Kombination ist der einzige React-Stack, dem ich für einen Solo-SaaS-Launch vertraue — typsicher End-to-End, Edge-Deployment und die Data-Fetching-Story, die ich sonst selbst hätte bauen müssen.

Wenn Sie eine bestehende App auf Next.js oder React Router haben, ist die Migration dokumentiert. Der Vergleich TanStack Router vs. React Router deckt die Router-Migration ab. Die Query-Migration ist mostly ein Search-and-Replace von useEffect für useQuery. Die Start-Migration ist ein Rewrite der API-Routes als Server Functions.

Wenn Sie ein durchgearbeitetes Beispiel wollen — Auth, Datenbank, Deployment — führt die TanStack Ship Features-Seite durch die Patterns. Der TanStack Ship Blog Index behandelt Postmortems, Vergleiche und die Patterns, die ich in Produktion eingesetzt habe. Fangen Sie dort an, bevor Sie mit dem Coden beginnen.