TanStack Start and Router: What You Need to Know

TanStack Start and Router: What You Need to Know

An overview of TanStack Start and TanStack Router — type-safe routing, validated search params, server functions, middleware, SSR, and how to get started.

Aurora Scharff

Aurora Scharff

April 9, 2026

TanStack Start is a full-stack React framework that has reached Release Candidate status. The State of React 2025 survey highlighted it as an emerging client-first framework, and adoption has been picking up since. Built on TanStack Router and Vite, its core focus is compile-time type safety and explicit control over how your application works.

This post covers what TanStack Router and Start do, how they work, and what to know if you're considering them. For a broader look at React frameworks, see React Frameworks and Server-Side Features: Beyond Client-Side Rendering.

TanStack Router: Type Safety All the Way Down

TanStack Router validates routes, parameters, and navigation at the TypeScript level.

Typed Routes and Params

Routes, path parameters, and navigation are all typed. Here's what a route definition looks like:

      export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    // params.postId is typed as string — no casting needed
    return fetchPost(params.postId)
  },
  component: PostComponent,
})

    

Navigation is type-checked too. If you try to link to a route that doesn't exist or forget a required parameter, the compiler catches it:

      <Link to="/posts/$postId" params={{ postId: '123' }}>
  View Post
</Link>

    

The goal is to catch broken links and mismatched params at compile time rather than discovering them at runtime.

Search Params as First-Class State

Search params go through the same validation and type system as the rest of the routing, rather than being untyped strings.

You define a schema using a validation library like Zod:

      import { z } from 'zod'

const productSearchSchema = z.object({
  page: z.number().default(1),
  category: z.string().default('all'),
  sortBy: z.enum(['price', 'name', 'rating']).default('name'),
})

export const Route = createFileRoute('/products')({
  validateSearch: productSearchSchema,
  component: ProductsPage,
})

    

Inside the component, search params are typed and validated automatically:

      function ProductsPage() {
  const { page, category, sortBy } = Route.useSearch()
  // All typed, all validated, all with defaults
}

    

This means the URL becomes your source of truth for things like filters and pagination. Users can bookmark filtered views, share links that preserve their exact state, and the back button works as expected.

Data Loading and Caching

TanStack Router uses a loader-based model for data fetching. Loaders run before components render, so the data is available by the time the component mounts.

      export const Route = createFileRoute('/posts')({
  loader: () => fetchPosts(),
  staleTime: 10_000,
  gcTime: 5 * 60_000,
  component: PostsPage,
})

function PostsPage() {
  const posts = Route.useLoaderData()
  // Data is already here — no loading spinner needed
}

    

The router includes built-in SWR (stale-while-revalidate) caching. Once data is loaded, navigating back to a route shows the cached version instantly while revalidating in the background. You can configure staleTime and gcTime per route to control how long data stays fresh.

For more advanced caching needs, TanStack Router integrates directly with TanStack Query:

      import { queryOptions } from '@tanstack/react-query'

const postQueryOptions = (postId: string) =>
  queryOptions({
    queryKey: ['post', postId],
    queryFn: () => fetchPost(postId),
  })

export const Route = createFileRoute('/posts/$postId')({
  loader: ({ context, params }) =>
    context.queryClient.ensureQueryData(postQueryOptions(params.postId)),
})

    

This combines route-level data loading with Query's caching, deduplication, and background refetching. For an example of using Suspense with TanStack Query's useSuspenseQuery, see Building an Async Combobox with useSuspenseQuery() and useDeferredValue().

Prefetching

TanStack Router supports automatic route prefetching with multiple strategies:

      const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
  defaultPreloadDelay: 50,
})

    

With intent prefetching, hovering over a link triggers prefetching of that route's code and data. Other strategies include prefetching on viewport entry or on render.

TanStack Start: The Full-Stack Layer

TanStack Router handles client-side routing. TanStack Start builds on top of it to add full-stack capabilities: server-side rendering, server functions, middleware, and deployment tooling.

Server Functions

Server functions let you write server-only logic that's callable from anywhere in your application — loaders, components, hooks, or other server functions. They're created with createServerFn and support both GET and POST, so they handle data fetching and mutations in one API. They also have built-in input validation and middleware:

      import { createServerFn } from '@tanstack/react-start'
import { z } from 'zod'

export const getTodos = createServerFn({ method: 'GET' })
  .inputValidator(z.object({ userId: z.string() }))
  .handler(async ({ data }) => {
    return db.todos.findMany({ where: { userId: data.userId } })
  })

    

You call this from client code like any other function — the types flow through automatically:

      const todos = await getTodos({ data: { userId: '123' } })
// todos is fully typed based on the handler's return type

    

Middleware

TanStack Start's middleware system supports two types: request middleware that runs for all server requests, and server function middleware that runs specifically for server functions.

Server function middleware can run on both the client and the server:

      import { createMiddleware } from '@tanstack/react-start'

const authMiddleware = createMiddleware({ type: 'function' })
  .client(async ({ next }) => {
    return next({
      headers: { Authorization: `Bearer ${getToken()}` },
    })
  })
  .server(async ({ next }) => {
    const user = await validateToken()
    return next({ context: { user } })
  })

    

This composability means you can chain authentication, logging, validation, and error handling without repetition. Middleware can be attached to individual server functions or applied globally to all requests.

SSR and Streaming

TanStack Start provides full-document SSR with streaming out of the box. You get server-side rendering for better performance and SEO, with the ability to stream content progressively using React's Suspense boundaries (covered in more detail in the frameworks post linked above).

One notable feature is selective SSR — you can control SSR behavior per route. Some routes can be fully server-rendered, some can be data-only (SPA-like with server data), and some can be purely client-rendered.

Deployment Flexibility

TanStack Start is built on Vite and uses Nitro for server deployment, which supports a range of hosting providers: Cloudflare Workers, Netlify, Vercel, AWS, Railway, Fly.io, and more.

Current Limitations

  • React Server Components: Not supported yet, but a composable approach to RSC was previewed at React Paris. Expected to ship as a non-breaking v1.x addition.
  • Ecosystem: The community is growing but still smaller than more established frameworks — fewer tutorials, starter templates, and third-party examples.
  • Maturity: The RC is feature-complete and the API is stable, but it's still new in production.

Getting Started

To try TanStack Start:

      npx @tanstack/cli@latest create

    

This scaffolds a project with TanStack Router, SSR, and Vite configured. From there you can add server functions, configure middleware, and start building routes.

If you want to try TanStack Router without the full-stack features, you can use it standalone as a client-side router:

      npm install @tanstack/react-router

    

The TanStack Start documentation includes guides for setup, server functions, middleware, and deployment.

Whichever framework you choose, the React fundamentals underneath remain the same. Understanding hooks, concurrent features, component architecture, and state management patterns transfers across all of them. The framework handles the plumbing — your React knowledge is what makes the application work well.


Sources:

More certificates.dev articles

Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.

Looking for Certified Developers?

We can help you recruit Certified Developers for your organization or project. The team has helped many customers employ suitable resources from a pool of 100s of qualified Developers.

Let us help you get the resources you need.

Contact Us
Customer Testimonial for Hiring
like a breath of fresh air
Everett Owyoung
Everett Owyoung
Head of Talent for ThousandEyes
(a Cisco company)