Files
2nd/10_Wiki/Topic_Programming/Coding/Frontend_TanStack_Start.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

8.0 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
frontend-tanstack-start TanStack Start — modern fullstack React Coding draft B conceptual 2026-05-09 2026-05-09
frontend
fullstack
vibe-coding
language applicable_to
TS / React
Frontend
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

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 정의

// 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 <h1>{post.title}</h1>;
}

→ Type-safe params (string id).

Search params (type-safe)

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 <div>Page {page}</div>;
}

→ URL ?page=1&sort=asc 가 type-safe.

Server function (RPC)

// 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)

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

export const Route = createFileRoute('/dashboard')({
  loader: async () => {
    const [user, stats] = await Promise.all([
      fetchUser(),
      fetchStats(),
    ]);
    return { user, stats };
  },
  pendingComponent: () => <Spinner />,
  errorComponent: ({ error }) => <Error error={error} />,
});

→ Suspense / error boundary 가 declarative.

Defer (streaming)

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 (
    <>
      <h1>{user.name}</h1>
      <Suspense fallback={<Spinner />}>
        <SlowComponent slowPromise={slow} />
      </Suspense>
    </>
  );
}

→ User 빠른 first paint, slow 가 streaming.

Layout (nested)

// src/routes/__root.tsx
import { Outlet } from '@tanstack/react-router';

export const Route = createRootRoute({
  component: () => (
    <>
      <Header />
      <Outlet />
      <Footer />
    </>
  ),
});

// src/routes/posts/__layout.tsx
export const Route = createFileRoute('/posts')({
  component: () => (
    <div className="posts-layout">
      <Sidebar />
      <Outlet />
    </div>
  ),
});

Route protection

// 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.
import { Link } from '@tanstack/react-router';

<Link
  to="/posts/$id"
  params={{ id: '123' }}
  search={{ tab: 'comments' }}
>
  View
</Link>

// ❌ Compile error — wrong route or param type.

Devtools

import { TanStackRouterDevtools } from '@tanstack/router-devtools';

<TanStackRouterDevtools />
// → 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

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

const createPostFn = createServerFn('POST', async (data: FormData) => {
  const title = data.get('title') as string;
  return db.posts.create({ data: { title } });
});

<form action={createPostFn}>
  <input name="title" />
  <button>Submit</button>
</form>

→ Native form action 식 (Remix 비슷).

Deploy

# 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 통합

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 <h1>{data.name}</h1>;
}

→ 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.

🔗 관련 문서