DEV Community

Alex Spinov
Alex Spinov

Posted on

TanStack Start Has a Free API: The Full-Stack React Framework From the TanStack Router Team

TanStack Start is a new full-stack React framework built on TanStack Router and Nitro. It combines type-safe routing, server functions, and SSR/SSG into one framework — with the same quality as TanStack Query.

Why TanStack Start?

  • Type-safe routing — routes are fully typed, including params and search
  • Server functions — call server code from client, RPC-style
  • Nitro-powered — deploy to 20+ platforms
  • TanStack Router — the best router in React ecosystem
  • File-based routing — with full type inference

Quick Start

npm create @tanstack/start my-app
cd my-app
npm install
npm run dev
Enter fullscreen mode Exit fullscreen mode

File-Based Routes (Type-Safe)

// routes/index.tsx
import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/')({ 
  component: HomePage,
});

function HomePage() {
  return <h1>Welcome to TanStack Start!</h1>;
}

// 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!
    const user = await fetchUser(params.userId);
    return { user };
  },
  component: UserPage,
});

function UserPage() {
  const { user } = Route.useLoaderData();
  return <div>{user.name}</div>; // Fully typed!
}
Enter fullscreen mode Exit fullscreen mode

Server Functions

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

// Runs on server, callable from client
const getUsers = createServerFn('GET', async () => {
  const users = await db.select().from(usersTable);
  return users;
});

const createUser = createServerFn('POST', async (input: { name: string; email: string }) => {
  const user = await db.insert(usersTable).values(input).returning();
  return user[0];
});

// Use in component
function UserList() {
  const users = Route.useLoaderData(); // From loader

  async function handleCreate() {
    const newUser = await createUser({ name: 'Alice', email: 'alice@example.com' });
    // Automatically revalidates
  }

  return (
    <div>
      {users.map(u => <div key={u.id}>{u.name}</div>)}
      <button onClick={handleCreate}>Add User</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Search Params (Type-Safe)

import { createFileRoute } from '@tanstack/react-router';
import { z } from 'zod';

const searchSchema = z.object({
  page: z.number().default(1),
  sort: z.enum(['name', 'date', 'popular']).default('date'),
  q: z.string().optional(),
});

export const Route = createFileRoute('/articles')({
  validateSearch: searchSchema,
  loader: async ({ search }) => {
    // search.page, search.sort, search.q — all typed!
    return fetchArticles(search);
  },
  component: ArticlesPage,
});

function ArticlesPage() {
  const { page, sort, q } = Route.useSearch(); // Typed!
  const navigate = Route.useNavigate();

  return (
    <div>
      <button onClick={() => navigate({ search: { sort: 'popular' } })}>
        Sort by Popular
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Key Features

Feature Details
Routing File-based, fully type-safe
Server Server functions (RPC)
SSR Streaming SSR + SSG
Deploy Nitro → 20+ platforms
Data Integrated with TanStack Query
Types End-to-end, params + search + data

Resources


Building React apps? Check my Apify actors or email spinov001@gmail.com.

Top comments (0)