DEV Community

Alex Spinov
Alex Spinov

Posted on

TanStack Start Has a Free API — Full-Stack React with Type-Safe Routing

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
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode
// 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>;
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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,
});
Enter fullscreen mode Exit fullscreen mode

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)