Getting Started with TanStack Start: A Practical Guide
When TanStack Start was announced, I was initially skeptical. We already have Next.js, Remix, and SvelteKit filling the meta-framework space — did we need another one? After building this portfolio site with it, I have a much more nuanced answer.
What makes it different
TanStack Start is built on Vite and TanStack Router, which means it inherits TanStack Router's best-in-class TypeScript support from day one. If you've used TanStack Router in a client-side SPA, the mental model transfers directly.
The file-based routing uses a createFileRoute pattern that feels slightly more explicit than Next.js's convention-over-configuration approach:
// src/routes/blog/$slug.tsx
export const Route = createFileRoute('/blog/$slug')({
component: BlogPost,
loader: async ({ params }) => {
return fetchPost(params.slug)
},
})
The loader runs on the server and its return type is fully inferred in the component — no casting or manual type annotations needed.
Server functions
The killer feature for me is server functions. You can define a function with createServerFn and call it from anywhere in your component tree, and it will run on the server with full type safety:
const getPost = createServerFn({ method: 'GET' })
.validator(z.object({ slug: z.string() }))
.handler(async ({ data }) => {
return db.post.findUnique({ where: { slug: data.slug } })
})
This is remarkably clean. No API route files, no fetch calls with manual error handling — just a typed function call.
The tradeoffs
TanStack Start is younger than Next.js, and it shows in some areas. The ecosystem of third-party integrations is smaller, and there are rough edges in the documentation. I hit a few confusing moments around SSR hydration that took some digging to resolve.
But for TypeScript-first teams who are already invested in the TanStack ecosystem, the ergonomics are genuinely superior. I'll be reaching for it on my next greenfield project.