---
id: frontend-tanstack-start
title: TanStack Start β modern fullstack React
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [frontend, fullstack, vibe-coding]
tech_stack: { language: "TS / React", applicable_to: ["Frontend"] }
applied_in: []
aliases: [TanStack Start, TanStack Router, server functions, Remix alternative, fullstack React]
---
# TanStack Start
> Next.js alternative. **TanStack Router (file-based) + Vite + server functions**. Full-stack React, type-safe end-to-end.
## π ν΅μ¬ κ°λ
- File-based routing (Next λΉμ·).
- Type-safe route params (search, path).
- Server functions (RPC μ).
- Vite κ° build (Next λ³΄λ€ simple).
## π» μ½λ ν¨ν΄
### Setup
```bash
npm create @tanstack/start@latest my-app
cd my-app
npm run dev
```
### File-based route
```
src/routes/
βββ __root.tsx # layout
βββ index.tsx # /
βββ about.tsx # /about
βββ posts/
β βββ index.tsx # /posts
β βββ $id.tsx # /posts/:id
βββ _authenticated/ # auth-required
βββ dashboard.tsx
```
### Route μ μ
```tsx
// src/routes/posts/$id.tsx
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/posts/$id')({
component: PostPage,
loader: ({ params }) => fetchPost(params.id),
});
function PostPage() {
const post = Route.useLoaderData();
const params = Route.useParams();
return
{post.title}
;
}
```
β Type-safe params (string `id`).
### Search params (type-safe)
```tsx
import { z } from 'zod';
export const Route = createFileRoute('/products')({
validateSearch: z.object({
page: z.number().default(1),
sort: z.enum(['asc', 'desc']).default('asc'),
}),
loader: ({ deps }) => fetchProducts(deps),
loaderDeps: ({ search }) => search,
component: Products,
});
function Products() {
const { page, sort } = Route.useSearch();
return Page {page}
;
}
```
β URL `?page=1&sort=asc` κ° type-safe.
### Server function (RPC)
```tsx
// src/routes/posts/$id.tsx
import { createServerFn } from '@tanstack/start';
export const getPost = createServerFn('GET', async (id: string) => {
return await db.posts.findUnique({ where: { id } });
});
// Client λλ server κ° νΈμΆ
const post = await getPost('abc');
```
β `getPost` κ° server-only β client bundle μ λ€μ΄κ°.
### Mutation (server function)
```tsx
export const createPost = createServerFn('POST', async (data: PostInput) => {
// Server-only
const session = useSession();
if (!session) throw new Error('unauthorized');
return db.posts.create({ data });
});
// Client
async function handleSubmit(data: PostInput) {
const post = await createPost(data);
}
```
### Loader + suspense
```tsx
export const Route = createFileRoute('/dashboard')({
loader: async () => {
const [user, stats] = await Promise.all([
fetchUser(),
fetchStats(),
]);
return { user, stats };
},
pendingComponent: () => ,
errorComponent: ({ error }) => ,
});
```
β Suspense / error boundary κ° declarative.
### Defer (streaming)
```tsx
export const Route = createFileRoute('/dashboard')({
loader: async () => {
const user = await fetchUser(); // λΉ λ¦ β wait
const slow = fetchSlow(); // promise β defer
return { user, slow };
},
});
function Dashboard() {
const { user, slow } = Route.useLoaderData();
return (
<>
{user.name}
}>
>
);
}
```
β User λΉ λ₯Έ first paint, slow κ° streaming.
### Layout (nested)
```tsx
// src/routes/__root.tsx
import { Outlet } from '@tanstack/react-router';
export const Route = createRootRoute({
component: () => (
<>
>
),
});
// src/routes/posts/__layout.tsx
export const Route = createFileRoute('/posts')({
component: () => (
),
});
```
### Route protection
```tsx
// src/routes/_authenticated.tsx
export const Route = createFileRoute('/_authenticated')({
beforeLoad: async ({ context }) => {
if (!context.user) throw redirect({ to: '/login' });
},
});
// src/routes/_authenticated/dashboard.tsx
// β user μμ΄μΌλ§ access.
```
### Link (type-safe)
```tsx
import { Link } from '@tanstack/react-router';
View
// β Compile error β wrong route or param type.
```
### Devtools
```tsx
import { TanStackRouterDevtools } from '@tanstack/router-devtools';
// β Route tree, search, params μκ°ν.
```
### vs Next.js
```
Next:
- App Router (RSC + Server Action)
- ν° ecosystem
- Vercel μΉν
TanStack Start:
- 100% type-safe
- File λλ code-based route
- Vite (μμ, λΉ λ¦)
- μμ ecosystem (newer)
```
β Type-safe + Vite = TanStack.
ν¬κ³ / RSC heavy / Vercel = Next.
### vs Remix
```
Remix:
- Loader / Action κ° file λ³
- Web standards μΉν (Form, Request)
TanStack:
- Loader κ° λΉμ·
- Server function κ° RPC μ
- Type-safety κ°ν¨
```
### vs SvelteKit / Nuxt
```
SvelteKit: Svelte μΉν.
Nuxt: Vue μΉν.
TanStack Start: React μΉν + κ°μ₯ type-safe.
```
### Middleware
```tsx
export const Route = createFileRoute('/admin')({
beforeLoad: async ({ location }) => {
const session = await getSession();
if (!session?.isAdmin) {
throw redirect({ to: '/login', search: { redirect: location.href } });
}
},
});
```
### Server function + form
```tsx
const createPostFn = createServerFn('POST', async (data: FormData) => {
const title = data.get('title') as string;
return db.posts.create({ data: { title } });
});
```
β Native form action μ (Remix λΉμ·).
### Deploy
```bash
# Vercel
npx vercel deploy
# Cloudflare
npx wrangler deploy
# Bun / Node server
node .output/server/index.mjs
```
### Use case
```
- μμ-μ€κ° React app
- Type-safety priority
- Vite μΉν (Next λ³΄λ€ λΉ λ₯Έ dev)
- Internal tool
- Solo / μμ ν
```
### vs Vite + React Router (no SSR)
```
Vite + React Router: λͺ¨λ κ±° client.
TanStack Start: SSR + server function.
β SEO / λΉ λ₯Έ first paint = Start.
```
### TanStack Query ν΅ν©
```tsx
import { queryOptions, useSuspenseQuery } from '@tanstack/react-query';
const userQuery = (id: string) => queryOptions({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
});
export const Route = createFileRoute('/users/$id')({
loader: ({ params, context }) => context.queryClient.ensureQueryData(userQuery(params.id)),
});
function User() {
const { id } = Route.useParams();
const { data } = useSuspenseQuery(userQuery(id));
return {data.name}
;
}
```
β Query + Router κ° best mate.
### Stage / status
```
2026-05: Start κ° still beta.
TanStack Router: stable (1.0+).
Server function: stable.
β Production OK κ° small / medium.
ν° = Next κ° mature.
```
## π€ μμ¬κ²°μ κΈ°μ€
| μν© | μΆμ² |
|---|---|
| New React + type-safety | TanStack Start |
| ν° enterprise | Next.js |
| Static / blog | Astro |
| μμ SPA | Vite + React Router |
| Internal admin | TanStack Start |
| Server-heavy | Next.js / Remix |
| Edge | TanStack / Astro |
## β μν°ν¨ν΄
- **Manual route λ±λ‘ + file-based λ λ€**: confused.
- **Server function μ client logic**: bundle νλ°.
- **Loader κ° ν°**: defer μ¬μ©.
- **Search param schema μμ**: κΉ¨μ§.
- **TanStack Query μμ΄ client cache**: refetch νλ°.
- **λͺ¨λ κ±° SSR**: client island λ OK.
## π€ LLM νμ© ννΈ
- TanStack Router κ° κ°μ₯ type-safe.
- Server function = RPC μ (Remix μ λΉμ·).
- TanStack Query μ deep integration.
- Vite + Start = simple stack.
## π κ΄λ ¨ λ¬Έμ
- [[React_TanStack_Router_Patterns]]
- [[React_TanStack_Query_Advanced]]
- [[React_Server_Components]]