SuperAPI AI Directory

start-execution-model

Coding & development

View repository

Updated 10-15 21:48

About this skill

Every module is isomorphic by default: it runs in BOTH server and client bundles, and route loaders run on both server (SSR) and client (navigation) — so DB access, filesystem, and secrets must live inside createServerFn or createServerOnlyFn, never a bare loader or module scope. process.env must be read per request, not at module scope, because module-level reads can leak into the client bundle and are undefined on edge runtimes that inject env at request time. VITE_/PUBLIC_-prefixed vars are exposed to the client, so server secrets must never carry that prefix.

Documents every environment-boundary API at a glance — createServerFn, createServerOnlyFn, createClientOnlyFn, createIsomorphicFn, , useHydrated(), and the server-only/client-only import markers — with a decision framework for which to use and complete copy-paste boundary examples.

Do NOT use this skill for initial project setup (use start-core) or for file/directory SOLID organization (use solid-tanstack-start).

TanStack Start Execution Model

Understanding where code runs is the single most important concept in Start, and the #1 source of AI-generated bugs. Targets @tanstack/react-start v1.168.58.

CRITICAL — everything is isomorphic by default. Every module runs in BOTH the server and client bundles. Route loaders run on both — during SSR AND during client navigation. DB, filesystem, and secrets MUST live inside createServerFn (or createServerOnlyFn), never a bare loader or module scope.

CRITICAL — read process.env per request, not at module scope. Module-level reads (1) can be inlined into the client bundle (secret leak) and (2) are undefined on edge runtimes (Cloudflare Workers inject env at request time).

CRITICAL — VITE_/PUBLIC_ prefixed vars are exposed to the client. Server secrets must have NO public prefix.

Agent Workflow (MANDATORY)

Verify APIs against Context7 (/websites/tanstack_start_framework_react) + Exa before writing boundary code. After changes, run fuse-ai-pilot:sniper.


The Boundary APIs at a Glance

API Use case Client behavior Server behavior
createServerFn() RPC, data, mutations network request direct execution
createServerOnlyFn(fn) server utility throws direct execution
createClientOnlyFn(fn) browser utility direct execution throws
createIsomorphicFn() per-env implementation .client() impl .server() impl
<ClientOnly fallback> browser-only UI renders children renders fallback
useHydrated() post-hydration logic true after hydrate false
import '@tanstack/react-start/server-only' whole file server-only import denied allowed
import '@tanstack/react-start/client-only' whole file client-only allowed import denied

All boundary creators are imported from @tanstack/react-start; <ClientOnly> and useHydrated come from @tanstack/react-router.


The One Gotcha to Remember

// ❌ WRONG — loader is isomorphic; SECRET ships to the browser
export const Route = createFileRoute('/dashboard')({
  loader: async () => {
    const secret = process.env.API_SECRET // leaked
    return fetch(url, { headers: { Authorization: secret } })
  },
})

// ✅ CORRECT — server-only work behind createServerFn
const getData = createServerFn({ method: 'GET' }).handler(async () => {
  const secret = process.env.API_SECRET // stays on the server
  return fetch(url, { headers: { Authorization: secret } })
})
export const Route = createFileRoute('/dashboard')({ loader: () => getData() })

Reference Guide

Topic Reference Load when
Why loaders/modules are isomorphic; the mental model references/isomorphic-by-default.md deciding server vs client vs both
Each boundary API + import markers + which to pick references/environment-boundaries.md choosing an API, marking a file
VITE_/PUBLIC_ vs process.env, per-request reads, runtime vars references/environment-variables.md env var undefined / leaked
Complete copy-paste examples of every boundary references/templates/boundaries.md writing boundary code

Decision Framework

  • Server-only (createServerFn / createServerOnlyFn): secrets, DB, filesystem, external API keys.
  • Client-only (createClientOnlyFn / <ClientOnly>): DOM, localStorage, geolocation, analytics.
  • Isomorphic (default / createIsomorphicFn): formatting, business logic, shared utilities, loaders.

Forbidden

  • DB / secrets / filesystem in a bare loader (→ createServerFn).
  • process.env at module scope (leak + undefined on edge).
  • VITE_/PUBLIC_ prefix on a secret.
  • Non-deterministic render output (new Date() directly) → hydration mismatch.
  • Dynamic import() of a *.functions.ts server function (bundler issues).