TanStack Start is the new full-stack React framework from the creator of TanStack Query, TanStack Router, and TanStack Table. Type-safe routing, server functions, and the best data-fetching story in React.
Why TanStack Start?
- 100% type-safe routing — route params, search params, all typed
-
Server functions — RPC-style backend calls with
createServerFn - TanStack Router — the most type-safe router in the React ecosystem
- TanStack Query — best-in-class data fetching, built in
Quick Start
npm create @tanstack/start myapp
cd myapp
npm install
npm run dev
File-Based Routing
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/')({ component: Home });
function Home() {
return <h1>Welcome to TanStack Start!</h1>;
}
// src/routes/users/$userId.tsx
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/users/$userId')({
loader: async ({ params }) => {
// params.userId is typed as string
return fetchUser(params.userId);
},
component: UserPage,
});
function UserPage() {
const user = Route.useLoaderData();
return <h1>{user.name}</h1>;
}
Server Functions
import { createServerFn } from '@tanstack/start';
const getUsers = createServerFn('GET', async () => {
return await db.select().from(users);
});
const createUser = createServerFn('POST', async (data: { name: string; email: string }) => {
return await db.insert(users).values(data).returning();
});
// Use in components
function UserList() {
const users = Route.useLoaderData(); // from loader
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
Type-Safe Search Params
import { createFileRoute } from '@tanstack/react-router';
import { z } from 'zod';
const searchSchema = z.object({
page: z.number().default(1),
sort: z.enum(['name', 'date']).default('name'),
filter: z.string().optional(),
});
export const Route = createFileRoute('/products')({
validateSearch: searchSchema,
component: Products,
});
function Products() {
const { page, sort, filter } = Route.useSearch();
// All typed! page: number, sort: 'name' | 'date', filter: string | undefined
}
Data Loading with Stale-While-Revalidate
export const Route = createFileRoute('/dashboard')({
loader: async () => {
return {
stats: await getStats(),
recentOrders: await getRecentOrders(),
};
},
staleTime: 30_000, // Revalidate every 30s
component: Dashboard,
});
Need real-time data for your React app? Check out my Apify actors for web scraping APIs, or email spinov001@gmail.com for custom data solutions.
TanStack Start, Next.js, or Remix — which React framework do you choose? Comment below!
Top comments (0)