Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Tanstack Start

ASecurity

TanStack Start, the full-stack React framework built on TanStack Router with Vite or Rsbuild. Use when setting up or reviewing a `@tanstack/react-start` project — the build-tool plugin, SSR and selective SSR, server functions (`createServerFn`), server routes, middleware, prerendering, SPA mode, environment variables, or deployment targets.

3 stars
0 votes
0 copies
0 views
Added 9/23/2026
ai-agentsgoshellreactnodegitapi

Works with

cliapi

Security Analysis

A100/100

Pro scans all 6 files and shows the line behind each finding

Scanned 9/23/2026

$npx -y skills add Firzus/agent-skills --skill tanstack-start --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Tanstack Start?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Tanstack Start
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/firzus-tanstack-start/badge)](https://www.skillsdirectory.com/skills/firzus-tanstack-start)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: tanstack-start
description: >-
  TanStack Start, the full-stack React framework built on TanStack Router with
  Vite or Rsbuild. Use when setting up or reviewing a `@tanstack/react-start`
  project — the build-tool plugin, SSR and selective SSR, server functions
  (`createServerFn`), server routes, middleware, prerendering, SPA mode,
  environment variables, or deployment targets.
---

# TanStack Start

Reference for TanStack Start, a full-stack React framework powered by TanStack
Router. Start adds full-document SSR, streaming, server functions, server
routes, middleware, and full-stack builds on top of Router; Router itself still
owns routing, loaders, search params, and navigation.

Routing belongs to the sibling skill — see
[tanstack-router](../tanstack-router/SKILL.md) for file-based routes, loaders,
search-param validation, and navigation. This skill covers only what Start adds
on top. For server-state caching inside components, see
[tanstack-query](../tanstack-query/SKILL.md).

Start is at Release Candidate stage: the API is considered stable and
feature-complete, but not bug-free.

Branch-specific references, loaded on demand:

- [server-functions.md](./server-functions.md) — `createServerFn`, validators,
  serialization, errors, redirects, streaming, static server functions.
- [middleware.md](./middleware.md) — request vs function middleware, context
  passing, global middleware in `src/start.ts`, CSRF.
- [server-routes.md](./server-routes.md) — HTTP endpoints defined with the
  `server` property on file routes.
- [rendering.md](./rendering.md) — selective SSR, SPA mode, static
  prerendering, and ISR-style cache headers.
- [deployment.md](./deployment.md) — hosting targets, environment variables,
  and build outputs.

## First Checks

1. Confirm `@tanstack/react-start` and `@tanstack/react-router` are installed,
   and which build tool the project uses — Vite
   (`@tanstack/react-start/plugin/vite`) or Rsbuild
   (`@tanstack/react-start/plugin/rsbuild`). The plugin import path and several
   config shapes differ between them.
2. Read the build config (`vite.config.ts` / `rsbuild.config.ts`) before
   changing anything: `prerender`, `spa`, `pages`, `serverFns`, and
   `server.build` all live in the `tanstackStart()` options.
3. Look for `src/start.ts`. If it exists, Start does **not** auto-install the
   CSRF middleware — that file owns global request and function middleware.
4. Find `src/router.tsx` (router creation) and `src/routes/__root.tsx` (the
   document shell with `HeadContent` and `Scripts`); both are required.
5. Check whether a host adapter plugin is already wired in (Cloudflare, Netlify,
   Nitro) — plugin order in the array matters.

## Project Setup

Scaffold with `npx @tanstack/cli@latest create`, or clone an official example
with `npx gitpick TanStack/router/tree/main/examples/react/start-basic`.

Minimal dependency set: `@tanstack/react-start`, `@tanstack/react-router`,
`react`, `react-dom`, plus the build tool (`vite` + `@vitejs/plugin-react`, or
`@rsbuild/core` + `@rsbuild/plugin-react`).

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'

export default defineConfig({
  server: { port: 3000 },
  plugins: [
    tanstackStart(),
    // react's vite plugin must come after start's vite plugin
    viteReact(),
  ],
})
```

Rules that bite:

- The React plugin must come **after** `tanstackStart()` in the Vite plugin
  array.
- `package.json` needs `"type": "module"`.
- In `tsconfig.json`, keep `verbatimModuleSyntax` **disabled** — enabling it can
  leak server bundles into client bundles. Use `"jsx": "react-jsx"`,
  `"moduleResolution": "Bundler"`, `"module": "ESNext"`, `strictNullChecks`.
- `src/routeTree.gen.ts` is generated on first run; do not hand-edit it.

Two files are required beyond the config:

```tsx
// src/router.tsx
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'

export function getRouter() {
  return createRouter({ routeTree, scrollRestoration: true })
}
```

```tsx
// src/routes/__root.tsx
import {
  createRootRoute,
  HeadContent,
  Outlet,
  Scripts,
} from '@tanstack/react-router'

export const Route = createRootRoute({
  head: () => ({
    meta: [{ charSet: 'utf-8' }, { title: 'App' }],
  }),
  component: () => (
    <html>
      <head>
        <HeadContent />
      </head>
      <body>
        <Outlet />
        <Scripts />
      </body>
    </html>
  ),
})
```

`HeadContent` and `Scripts` are not optional: without them, head tags and the
client bundle never reach the document.

## Server Functions vs Server Routes

Both run on the server; they answer different questions.

| Need | Use | Why |
|------|-----|-----|
| Call server logic from your own app (loaders, components, handlers) | `createServerFn` | Start handles serialization and typing across the boundary. |
| An HTTP endpoint called from outside the app (webhooks, third parties, OAuth callbacks) | Server route (`server.handlers` on a file route) | Raw `Request`/`Response`, no Start client required. |

Server functions are same-origin RPC endpoints protected by CSRF checks; they
are not a public API surface. Server routes are.

```tsx
import { createServerFn } from '@tanstack/react-start'
import { z } from 'zod'

const CreateUser = z.object({ name: z.string().min(1) })

export const createUser = createServerFn({ method: 'POST' })
  .validator(CreateUser)
  .handler(async ({ data }) => {
    return db.users.create(data)
  })
```

Details in [server-functions.md](./server-functions.md) and
[server-routes.md](./server-routes.md).

## Where Code Runs

Route `loader` and `beforeLoad` are **isomorphic**: they run on the server for
the initial request and on the client for subsequent navigations. Reading
`process.env.SECRET` in a loader exposes it to the client bundle. Put
server-only work behind a server function.

```tsx
import {
  createServerOnlyFn,
  createClientOnlyFn,
  createIsomorphicFn,
} from '@tanstack/react-start'

const getSecret = createServerOnlyFn(() => process.env.API_SECRET)
const saveLocal = createClientOnlyFn((v: string) => localStorage.setItem('k', v))
const log = createIsomorphicFn()
  .server((m: string) => console.log(`[SERVER] ${m}`))
  .client((m: string) => console.log(`[CLIENT] ${m}`))
```

Server functions can be statically imported anywhere, including client
components — the build replaces the implementation with an RPC stub. Avoid
`await import()` of server-function modules; dynamic imports break that
transformation.

## Rendering Strategy

Every route matching the initial request is server-rendered by default. Narrow
it per route with `ssr`:

| Value | `beforeLoad` / `loader` on server | Component SSR |
|-------|-----------------------------------|---------------|
| `true` (default) | yes | yes |
| `'data-only'` | yes | no |
| `false` | no | no |

Change the app-wide default with `defaultSsr` in `createStart`. Inheritance is
one-way: a child can only make the inherited value **more** restrictive, so
`ssr: true` under a parent with `ssr: false` has no effect.

For a fully client-rendered app, use SPA mode (`spa: { enabled: true }`), which
prerenders a shell to `/_shell.html`. See [rendering.md](./rendering.md).

## Middleware

`createMiddleware()` produces request middleware, which runs for every server
request including SSR and server functions.
`createMiddleware({ type: 'function' })` produces server-function middleware,
which additionally supports `.client()` and `.validator()`.

```tsx
import { createMiddleware } from '@tanstack/react-start'

export const authMiddleware = createMiddleware().server(
  async ({ next, request }) => {
    const session = await auth.getSession({ headers: request.headers })
    if (!session) throw new Error('Unauthorized')
    return next({ context: { session } })
  },
)
```

Always call `next()`; the chain stops otherwise. Attach auth middleware to
every server function that reads or writes private data — a route `beforeLoad`
guard is UX, not the data boundary, because server functions are reachable
independently of the UI that calls them. Full model in
[middleware.md](./middleware.md).

## Environment Variables

Start loads `.env`, `.env.development`, `.env.production`, and `.env.local`
automatically.

- Server code reads any variable from `process.env`.
- Client code only sees the build tool's public prefix: `VITE_` for Vite,
  `PUBLIC_` for Rsbuild, via `import.meta.env`.
- Read `process.env` **inside** handlers and middleware, not at module scope.
  On Cloudflare Workers and similar edge runtimes, env is injected per request,
  so module-scope reads evaluate to `undefined`.
- To get a runtime (not build-time) value to the client, return it from a
  server function and pass it through a loader.

More, including typing and `staticNodeEnv`, in [deployment.md](./deployment.md).

## Review Checklist

- Build config is coherent: `tanstackStart()` before the React plugin (Vite),
  `"type": "module"`, `verbatimModuleSyntax` disabled.
- `__root.tsx` renders `HeadContent` and `Scripts`; `routeTree.gen.ts` is
  generated, not hand-edited.
- Every server function has a `.validator()` when it takes input, and the
  validated value is checked for **authorization**, not just shape — a
  well-formed id is not an authorized id.
- Auth middleware is attached to the server functions and server routes that
  touch private data, not only to route `beforeLoad`.
- `src/start.ts`, when present, installs `createCsrfMiddleware()` explicitly.
- No secret is read at module scope, and no secret sits behind a `VITE_` or
  `PUBLIC_` prefix.
- Loaders contain no server-only assumptions; server work goes through
  `createServerFn` or `createServerOnlyFn`.
- `Cache-Control` on anything identity-dependent is `private` or `no-store`,
  never `public` ([rendering.md](./rendering.md)).
- Routes needing browser APIs set `ssr: false` or `'data-only'` and provide a
  `pendingComponent` fallback.
- SPA-mode and static-host redirects allow `/_serverFn/*` and server-route
  paths through to the server ([rendering.md](./rendering.md)).
- Deployment target matches the build output and start script
  ([deployment.md](./deployment.md)).

Attribution

FirzusFirzus
View sourceSee grades on GitHubMore from Firzus →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698621 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →