### Clone and run the Basic TanStack Start example
Source: https://tanstack.com/start/latest/docs/framework/solid/getting-started.md
This sequence of commands clones the 'start-basic' example, installs its dependencies, and starts the development server.
```bash
npx gitpick TanStack/router/tree/main/examples/solid/start-basic start-basic
cd start-basic
npm install
npm run dev
```
--------------------------------
### Install Dependencies and Start Development Server
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/fetching-external-api
Install project dependencies and start the development server to run the TanStack Start application locally.
```bash
pnpm i
pnpm dev
```
--------------------------------
### Clone and run a generic TanStack Start example
Source: https://tanstack.com/start/latest/docs/framework/solid/getting-started.md
Replace `EXAMPLE_SLUG` with the desired example slug to clone and run any official TanStack Start example.
```bash
npx gitpick TanStack/router/tree/main/examples/solid/EXAMPLE_SLUG my-new-project
cd my-new-project
npm install
npm run dev
```
--------------------------------
### Install TanStack Start and core dependencies
Source: https://tanstack.com/start/latest/docs/framework/solid/build-from-scratch.md
Install TanStack Start, TanStack Router, and Vite as required dependencies.
```shell
npm i @tanstack/solid-start @tanstack/solid-router vite
```
--------------------------------
### Install Netlify Vite plugin
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Install the Netlify plugin for TanStack Start to configure builds and enable local production emulation.
```bash
npm install --save-dev @netlify/vite-plugin-tanstack-start
# or...
pnpm add --save-dev @netlify/vite-plugin-tanstack-start
```
--------------------------------
### Install TanStack Start and TanStack Router
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Install the core TanStack Start and TanStack Router packages as dependencies.
```shell
npm i @tanstack/react-start @tanstack/react-router
```
--------------------------------
### Initialize TanStack Start project with Solid
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/reading-writing-file.md
Use the TanStack CLI to scaffold a new project. You can optionally include add-ons like TanStack Query or Clerk during setup.
```bash
pnpx @tanstack/cli@latest create --framework solid devjokes
cd devjokes
```
--------------------------------
### Initialize project via TanStack CLI
Source: https://tanstack.com/start/latest/docs/framework/react/getting-started
Run this command to start an interactive setup for your project, including package manager and CSS framework selection.
```bash
npx @tanstack/cli@latest create
```
--------------------------------
### Install TanStack Start and Tailwind Dependencies
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Install core TanStack Start packages along with Vite and Tailwind CSS plugins.
```shell
npm i @tanstack/react-router @tanstack/react-start nitro vite @vitejs/plugin-react
```
```shell
npm i -D @tailwindcss/vite tailwindcss
```
--------------------------------
### Generate llms.txt File in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
This example demonstrates how to create a server-side route in TanStack Start to serve a 'llms.txt' file. This file provides guidance to AI systems, similar to 'robots.txt'.
```ts
// src/routes/llms[.]txt.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/llms.txt')({
server: {
handlers: {
GET: async () => {
const content = `# My App
> My App is a platform for building modern web applications.
## Documentation
- Getting Started: https://myapp.com/docs/getting-started
- API Reference: https://myapp.com/docs/api
`
return new Response(content, {
headers: {
'Content-Type': 'text/plain',
},
})
},
},
},
})
```
--------------------------------
### Implement FAQ Schema in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
This example shows how to dynamically generate 'FAQPage' Schema.org markup from fetched data within a TanStack Start route. It's particularly effective for LLMs to extract Q&A pairs.
```tsx
export const Route = createFileRoute('/faq')({
loader: async () => {
const faqs = await fetchFAQs()
return { faqs }
},
head: ({ loaderData }) => ({
meta: [{ title: 'Frequently Asked Questions' }],
scripts: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: loaderData.faqs.map((faq) => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer,
},
})),
}),
},
],
}),
component: FAQPage,
})
```
--------------------------------
### Install Netlify Vite Plugin for TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Install the official Netlify plugin that configures your build for Netlify deployment and provides local dev emulation.
```bash
npm install --save-dev @netlify/vite-plugin-tanstack-start
# or...
pnpm add --save-dev @netlify/vite-plugin-tanstack-start
# or yarn, bun, etc.
```
--------------------------------
### Bun Server Startup Output Example
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Example log output showing asset preloading status, file sizes, and the local server URL.
```text
📦 Loading static assets from ./dist/client...
Max preload size: 5.00 MB
📁 Preloaded into memory:
/assets/index-a1b2c3d4.js 45.23 kB │ gzip: 15.83 kB
/assets/index-e5f6g7h8.css 12.45 kB │ gzip: 4.36 kB
💾 Served on-demand:
/assets/vendor-i9j0k1l2.js 245.67 kB │ gzip: 86.98 kB
✅ Preloaded 2 files (57.68 KB) into memory
🚀 Server running at http://localhost:3000
```
--------------------------------
### Run Development Server
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Start the TanStack Start development server to verify the migration is working correctly.
```sh
npm run dev
```
--------------------------------
### Logging in TanStack Start Server Functions
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
This example shows how to add detailed logging within a `createServerFn` handler to track execution flow, performance, and errors for individual server function calls.
```tsx
import { createServerFn } from '@tanstack/solid-start'
const getUser = createServerFn({ method: 'GET' })
.inputValidator((id: string) => id)
.handler(async ({ data: id }) => {
const startTime = Date.now()
try {
console.log(`[SERVER] Fetching user ${id}`)
const user = await db.users.findUnique({ where: { id } })
if (!user) {
console.log(`[SERVER] User ${id} not found`)
throw new Error('User not found')
}
const duration = Date.now() - startTime
console.log(`[SERVER] User ${id} fetched in ${duration}ms`)
return user
} catch (error) {
const duration = Date.now() - startTime
console.error(
`[SERVER] Error fetching user ${id} after ${duration}ms:`,
error,
)
throw error
}
})
```
--------------------------------
### Build and Start TanStack Start Application (Node.js/Docker)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Execute these commands to build your application and then start the server using the configured npm scripts for Node.js/Docker deployments.
```sh
npm run build
```
```sh
npm run start
```
--------------------------------
### Install Vite as dev dependency
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Install Vite as a development dependency, which powers TanStack Start.
```shell
npm i -D vite
```
--------------------------------
### Install SolidJS and Vite plugin
Source: https://tanstack.com/start/latest/docs/framework/solid/build-from-scratch.md
Install SolidJS and the Vite plugin for SolidJS support.
```shell
npm i solid-js vite-plugin-solid
```
--------------------------------
### Build and Start Production Server with Bun
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Use these commands to build your application and then start the custom Bun production server, which can be configured via environment variables.
```sh
bun run build
```
```sh
bun run server.ts
```
--------------------------------
### Create TanStack Start Project
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/fetching-external-api
Initialize a new TanStack Start project with the create-start-app CLI tool. Optionally pass --add-on flag for additional integrations like Shadcn, Clerk, or TanStack Query.
```bash
pnpx create-start-app movie-discovery
cd movie-discovery
```
--------------------------------
### Define a simple GET server route in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
This snippet demonstrates how to create a basic server-side GET endpoint using `createFileRoute` within a TypeScript file, returning a simple 'Hello, World!' response.
```typescript
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return new Response('Hello, World!')
},
},
},
})
```
--------------------------------
### Define Server Route with Simple GET Handler in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Configure a server route using `createFileRoute` and define a basic GET handler directly within the `handlers` object for straightforward request processing.
```ts
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
}
}
}
})
```
```ts
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
}
}
}
})
```
--------------------------------
### Install Nitro for Multi-Host Deployment
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Install Nitro to enable deployment of TanStack Start applications to a wide range of hosting providers.
```bash
npm install nitro
```
--------------------------------
### TanStack Start Root Route and Document Setup
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-trellaux
Defines the root route with context, SEO metadata, global layout, and integration with TanStack Devtools and React Query.
```tsx
///
import { ReactQueryDevtools } from '@tanstack/react-query-devtools/production'
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRouteWithContext,
useRouterState,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import * as React from 'react'
import { Toaster } from 'react-hot-toast'
import type { QueryClient } from '@tanstack/react-query'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { IconLink } from '~/components/IconLink'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
import { Loader } from '~/components/Loader'
export const Route = createRootRouteWithContext<{
queryClient: QueryClient
}>()({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Trellaux
a TanStack Demo
{/*
*/}
{children}
)
}
function LoadingIndicator() {
const isLoading = useRouterState({ select: (s) => s.isLoading })
return (
```
--------------------------------
### Create a new TanStack Start project using the CLI
Source: https://tanstack.com/start/latest/docs/framework/solid/getting-started.md
Use this command to scaffold a new TanStack Start project with the CLI, specifying the desired framework.
```bash
npx @tanstack/cli@latest create --framework solid
```
--------------------------------
### Clone and run official examples
Source: https://tanstack.com/start/latest/docs/framework/react/getting-started
Use gitpick to clone specific starter templates from the repository. Replace EXAMPLE_SLUG with a specific slug to clone other variants.
```bash
npx gitpick TanStack/router/tree/main/examples/react/start-basic start-basic
cd start-basic
npm install
npm run dev
```
```bash
npx gitpick TanStack/router/tree/main/examples/react/EXAMPLE_SLUG my-new-project
cd my-new-project
npm install
npm run dev
```
--------------------------------
### Install React and React DOM
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Install React and React DOM as dependencies for building the application.
```shell
npm i react react-dom
```
--------------------------------
### Define a basic server route handler
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Create a server route by adding a server property to createFileRoute. This example defines a simple GET handler that returns a Response.
```ts
// routes/hello.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
},
},
},
})
```
--------------------------------
### Root Route with Clerk Auth in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-clerk-basic
Complete root route setup with Clerk authentication integration. Fetches user ID server-side via createServerFn, wraps app in ClerkProvider, and provides conditional rendering for authenticated/unauthenticated users. Includes metadata configuration, error boundaries, and navigation.
```TypeScript
///
import {
ClerkProvider,
SignInButton,
SignedIn,
SignedOut,
UserButton,
} from '@clerk/tanstack-react-start'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import { createServerFn } from '@tanstack/react-start'
import { auth } from '@clerk/tanstack-react-start/server'
import * as React from 'react'
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary.js'
import { NotFound } from '~/components/NotFound.js'
import appCss from '~/styles/app.css?url'
const fetchClerkAuth = createServerFn({ method: 'GET' }).handler(async () => {
const { userId } = await auth()
return {
userId,
}
})
export const Route = createRootRoute({
beforeLoad: async () => {
const { userId } = await fetchClerkAuth()
return {
userId,
}
},
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{children}
)
}
```
--------------------------------
### Example .env File for Default Variables
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
This .env file contains default public and server configuration templates, intended to be committed to the repository.
```bash
# Public configuration
VITE_APP_NAME=My TanStack Start App
VITE_API_URL=https://api.example.com
VITE_SENTRY_DSN=https://...
# Server configuration templates
DATABASE_URL=postgresql://localhost:5432/myapp_dev
REDIS_URL=redis://localhost:6379
```
--------------------------------
### Install content-collections Dependencies
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Install the core and Vite integration packages for `content-collections` to process static markdown at build time.
```bash
npm install @content-collections/core @content-collections/vite
```
--------------------------------
### Next.js Server Action example
Source: https://tanstack.com/start/latest/docs/framework/react/comparison
Basic server action that runs on the server when called from a client component. Lacks input validation and middleware support compared to TanStack Start.
```TypeScript
'use server'
export async function getTodos(userId: string) {
// Runs on server, called from client
return db.todos.findMany({ where: { userId } })
}
// Call from client component
const todos = await getTodos('123')
```
--------------------------------
### Install Tailwind CSS v4 and Vite Plugin
Source: https://tanstack.com/start/latest/docs/framework/react/guide/tailwind-integration
Install Tailwind CSS version 4 and its Vite plugin for TanStack Start projects.
```shell
npm install tailwindcss @tailwindcss/vite
```
--------------------------------
### Create a new TanStack Start project
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/reading-writing-file
Initializes a new TanStack Start project named 'devjokes' and navigates into its directory. This command sets up the basic project structure.
```bash
pnpx @tanstack/cli@latest create devjokes
cd devjokes
```
--------------------------------
### Deploy to Netlify Using CLI
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Deploy your TanStack Start application to Netlify using the Netlify CLI command.
```bash
npx netlify deploy
```
--------------------------------
### Install srvx performance library
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Install the srvx package to access optimized server responses for Node.js environments.
```bash
pnpm install srvx
```
--------------------------------
### Configure Vite with TanStack Start plugin
Source: https://tanstack.com/start/latest/docs/framework/solid/build-from-scratch.md
Set up vite.config.ts with TanStack Start and SolidJS plugins. The SolidJS plugin must come after the TanStack Start plugin.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
import viteSolid from 'vite-plugin-solid'
export default defineConfig({
server: {
port: 3000,
},
resolve: {
tsconfigPaths: true,
},
plugins: [
tanstackStart(),
// solid's vite plugin must come after start's vite plugin
viteSolid({ ssr: true }),
],
})
```
--------------------------------
### Composing Middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Demonstrates how to compose middleware, where one middleware depends on another, creating a hierarchical chain of operations. This example shows 'authMiddleware' depending on 'loggingMiddleware'.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
const authMiddleware = createMiddleware()
.middleware([loggingMiddleware])
.server(() => {
//...
})
```
--------------------------------
### Environment File Hierarchy
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
TanStack Start loads environment files in a specific order, allowing for local overrides and environment-specific configurations.
```text
.env.local # Local overrides (add to .gitignore)
.env.production # Production-specific variables
.env.development # Development-specific variables
.env # Default variables (commit to git)
```
--------------------------------
### Create Server Functions for File I/O in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/reading-writing-file.md
Use createServerFn with GET and POST methods to read from and write to a local JSON file. Includes input validation and unique ID generation using UUID.
```tsx
// src/serverActions/jokesActions.ts
import { createServerFn } from '@tanstack/solid-start'
import * as fs from 'node:fs'
import { v4 as uuidv4 } from 'uuid' // Add this import
import type { Joke, JokesData } from '../types'
const JOKES_FILE = 'src/data/jokes.json'
export const getJokes = createServerFn({ method: 'GET' }).handler(async () => {
const jokes = await fs.promises.readFile(JOKES_FILE, 'utf-8')
return JSON.parse(jokes) as JokesData
})
// Add this new server function
export const addJoke = createServerFn({ method: 'POST' })
.inputValidator((data: { question: string; answer: string }) => {
// Validate input data
if (!data.question || !data.question.trim()) {
throw new Error('Joke question is required')
}
if (!data.answer || !data.answer.trim()) {
throw new Error('Joke answer is required')
}
return data
})
.handler(async ({ data }) => {
try {
// Read the existing jokes from the file
const jokesData = await getJokes()
// Create a new joke with a unique ID
const newJoke: Joke = {
id: uuidv4(),
question: data.question,
answer: data.answer,
}
// Add the new joke to the list
const updatedJokes = [...jokesData, newJoke]
// Write the updated jokes back to the file
await fs.promises.writeFile(
JOKES_FILE,
JSON.stringify(updatedJokes, null, 2),
'utf-8',
)
return newJoke
} catch (error) {
console.error('Failed to add joke:', error)
throw new Error('Failed to add joke')
}
})
```
--------------------------------
### Common Server Configuration with Custom Port and Logging
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Run TanStack Start server with custom port and verbose asset preloading logging to monitor server startup behavior.
```bash
PORT=8080 bun run server.ts # Custom port
```
```bash
ASSET_PRELOAD_VERBOSE_LOGGING=true bun run server.ts # See what's happening
```
--------------------------------
### TanStack Start project directory structure
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/reading-writing-file.md
Overview of the generated project layout, highlighting key files for routing and layout configuration.
```text
/devjokes
├── src/
│ ├── routes/
│ │ ├── demo/ # Demo routes
│ │ ├── __root.tsx # Root layout
│ │ └── index.tsx # Home page
│ ├── components/ # Solid components
│ ├── data/ # Data files
│ ├── router.tsx # Router configuration
│ ├── routeTree.gen.ts # Generated route tree
│ └── styles.css # Global styles
├── public/ # Static assets
├── vite.config.ts # TanStack Start configuration
├── package.json # Project dependencies
└── tsconfig.json # TypeScript configuration
```
--------------------------------
### Configure Vite with TanStack Start plugin
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Set up vite.config.ts with TanStack Start and React Vite plugins. The React plugin must come after the Start plugin in the plugins array.
```typescript
// 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,
},
resolve: {
tsconfigPaths: true,
},
plugins: [
tanstackStart(),
// react's vite plugin must come after start's vite plugin
viteReact(),
],
})
```
--------------------------------
### Configure npm Scripts for Node.js/Docker Deployment
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Define `build` and `start` scripts in your `package.json` to build and run your TanStack Start application in a Node.js/Docker environment.
```json
"build": "vite build",
"start": "node .output/server/index.mjs"
```
--------------------------------
### Root Route with Supabase Authentication in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-supabase-basic
Defines the root route with beforeLoad hook that fetches authenticated user from Supabase, configures head metadata, error boundaries, and renders navigation with conditional auth links. Requires Supabase client setup and TanStack Router/Start packages.
```TypeScript
///
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import { createServerFn } from '@tanstack/react-start'
import * as React from 'react'
import { DefaultCatchBoundary } from '../components/DefaultCatchBoundary'
import { NotFound } from '../components/NotFound'
import appCss from '../styles/app.css?url'
import { seo } from '../utils/seo'
import { getSupabaseServerClient } from '../utils/supabase'
const fetchUser = createServerFn({ method: 'GET' }).handler(async () => {
const supabase = getSupabaseServerClient()
const { data, error: _error } = await supabase.auth.getUser()
if (!data.user?.email) {
return null
}
return {
email: data.user.email,
}
})
export const Route = createRootRoute({
beforeLoad: async () => {
const user = await fetchUser()
return {
user,
}
},
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
const { user } = Route.useRouteContext()
return (
Home
{' '}
Posts
{user ? (
<>
{user.email}
Logout
>
) : (
Login
)}
{children}
)
}
```
--------------------------------
### Run TanStack Start Server with New Relic Agent (Bash)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Executes the compiled TanStack Start server using Node.js, preloading the New Relic agent for monitoring.
```bash
node -r newrelic .output/server/index.mjs
```
--------------------------------
### Define a POST server route with a React component in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
This example shows how to combine a server-side POST handler with a React component in the same file. The component includes a button that makes a POST request to the defined server route.
```tsx
// routes/hello.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
POST: async ({ request }) => {
const body = await request.json()
return new Response(JSON.stringify({ message: `Hello, ${body.name}!` }))
},
},
},
component: HelloComponent,
})
function HelloComponent() {
const [reply, setReply] = useState('')
return (
)
}
```
--------------------------------
### Install Fontsource Variable Fonts
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Install variable font packages from Fontsource as a replacement for next/font/google.
```sh
npm i -D @fontsource-variable/dm-sans @fontsource-variable/jetbrains-mono
```
--------------------------------
### Install Markdown Processing Dependencies
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Install the necessary packages for markdown parsing, transformation, and HTML rendering using the unified ecosystem.
```bash
npm install unified remark-parse remark-gfm remark-rehype rehype-raw rehype-slug rehype-autolink-headings rehype-stringify shiki html-react-parser gray-matter
```
--------------------------------
### Install TypeScript and type definitions
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Install TypeScript and type definitions for React, React DOM, and Node.js as dev dependencies.
```shell
npm i -D typescript @types/react @types/react-dom @types/node
```
--------------------------------
### Provide Context to Next Middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
This example shows how to pass an object with a `context` property to the `next` function within a server-side middleware. The context properties are merged and available to subsequent middleware.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const awesomeMiddleware = createMiddleware({ type: 'function' }).server(
({ next }) => {
return next({
context: {
isAwesome: Math.random() > 0.5,
},
})
},
)
const loggingMiddleware = createMiddleware({ type: 'function' })
.middleware([awesomeMiddleware])
.server(async ({ next, context }) => {
console.log('Is awesome?', context.isAwesome)
return next()
})
```
--------------------------------
### TanStack Start Configuration Properties
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
Configuration settings for managing file exclusions and violation callbacks within the TanStack Start environment.
```APIDOC
## CONFIGURATION TanStack Start
### Description
Configuration options for the TanStack Start server and violation handling.
### Parameters
#### Configuration Fields
- **server.excludeFiles** (Pattern[]) - Optional - Resolved files matching these patterns skip resolved-target checks (file-pattern + marker). This replaces the default exclusion list. Default: ['**/node_modules/**']
- **onViolation** (function) - Optional - Callback invoked on every violation. Default: undefined
```
--------------------------------
### Basic Client Hydration with StartClient
Source: https://tanstack.com/start/latest/docs/framework/react/guide/client-entry-point.md
Use this default setup to hydrate the root of your application and enable client-side routing after the initial server request.
```tsx
// src/client.tsx
import { StartClient } from '@tanstack/react-start/client'
import { StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'
hydrateRoot(
document,
,
)
```
--------------------------------
### TanStack Start Root Application Configuration and Components
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-supabase-basic
This snippet defines the main application configuration for a TanStack Start project, including document metadata, SEO, error handling, and the root component structure with navigation and user authentication display.
```javascript
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack Solid Framework',
description: `TanStack Start is a type-safe, client-first, full-stack Solid framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: Solid.JSX.Element }) {
const { user } = Route.useRouteContext()()
return (
Home
{' '}
Posts
{user ? (
<>
{user.email}
Logout
>
) : (
Login
)}
{children}
)
}
```
--------------------------------
### Advanced configurations for Bun production server
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Examples demonstrating advanced environment variable settings for the Bun production server, including memory optimization, asset preloading patterns, and disabling features.
```sh
ASSET_PRELOAD_MAX_SIZE=1048576 bun run server.ts
```
```sh
ASSET_PRELOAD_INCLUDE_PATTERNS="*.js,*.css" \
ASSET_PRELOAD_EXCLUDE_PATTERNS="*.map,vendor-*" \
bun run server.ts
```
```sh
ASSET_PRELOAD_ENABLE_ETAG=false \
ASSET_PRELOAD_ENABLE_GZIP=false \
bun run server.ts
```
--------------------------------
### Authentication Provider Setup with Environment Variables
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Illustrates configuring an authentication provider, separating server-side secrets (AUTH_SECRET, AUTH0_CLIENT_SECRET) from client-side public keys (VITE_AUTH0_DOMAIN, VITE_AUTH0_CLIENT_ID).
```typescript
// src/lib/auth.ts (Server)
export const authConfig = {
secret: process.env.AUTH_SECRET,
providers: {
auth0: {
domain: process.env.AUTH0_DOMAIN,
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET, // Server-only
}
}
}
```
```typescript
// src/components/AuthProvider.tsx (Client)
export function AuthProvider({ children }: { children: React.ReactNode }) {
return (
{children}
)
}
```
--------------------------------
### Configure vite.config.ts for TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Set up the Vite configuration with the TanStack Start plugin, including custom route directory settings.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
import { nitro } from 'nitro/vite'
export default defineConfig({
server: {
port: 3000,
},
resolve: {
// Enables Vite to resolve imports using path aliases.
tsconfigPaths: true,
},
plugins: [
tailwindcss(),
tanstackStart({
srcDirectory: 'src', // This is the default
router: {
// Specifies the directory TanStack Router uses for your routes.
routesDirectory: 'app', // Defaults to "routes", relative to srcDirectory
},
}),
viteReact(),
nitro(),
],
})
```
--------------------------------
### Create a Server Function to Read Files in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/reading-writing-file
Use createServerFn with the GET method to read local files using Node.js fs module. Ensure the handler returns data compatible with your defined types.
```tsx
// src/serverActions/jokesActions.ts
import { createServerFn } from '@tanstack/react-start'
import * as fs from 'node:fs'
import type { JokesData } from '../types'
const JOKES_FILE = 'src/data/jokes.json'
export const getJokes = createServerFn({ method: 'GET' }).handler(async () => {
const jokes = await fs.promises.readFile(JOKES_FILE, 'utf-8')
return JSON.parse(jokes) as JokesData
})
```
--------------------------------
### Middleware execution order and dependency resolution
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Middleware executes dependency-first, starting with global middleware followed by specific function middleware. This example demonstrates the logging sequence for nested and chained middleware dependencies.
```tsx
import { createMiddleware, createServerFn } from '@tanstack/solid-start'
const globalMiddleware1 = createMiddleware({ type: 'function' }).server(
async ({ next }) => {
console.log('globalMiddleware1')
return next()
},
)
const globalMiddleware2 = createMiddleware({ type: 'function' }).server(
async ({ next }) => {
console.log('globalMiddleware2')
return next()
},
)
const a = createMiddleware({ type: 'function' }).server(async ({ next }) => {
console.log('a')
return next()
})
const b = createMiddleware({ type: 'function' })
.middleware([a])
.server(async ({ next }) => {
console.log('b')
return next()
})
const c = createMiddleware({ type: 'function' })
.middleware()
.server(async ({ next }) => {
console.log('c')
return next()
})
const d = createMiddleware({ type: 'function' })
.middleware([b, c])
.server(async () => {
console.log('d')
})
const fn = createServerFn()
.middleware([d])
.server(async () => {
console.log('fn')
})
```
--------------------------------
### Creating a Basic Request Middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Shows how to define a simple request middleware using 'createMiddleware().server()' to customize the behavior of any server request.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
```
--------------------------------
### Common configurations for Bun production server
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Examples of common environment variables to configure the Bun production server, such as custom port or verbose logging.
```sh
PORT=8080 bun run server.ts
```
```sh
ASSET_PRELOAD_VERBOSE_LOGGING=true bun run server.ts
```
--------------------------------
### Install Wrangler CLI
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Install the Wrangler CLI locally to manage Cloudflare Workers deployments.
```bash
pnpm add wrangler -D
```
--------------------------------
### Single Dynamic Path Parameter in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Create a server route with a single dynamic parameter using the $id naming convention. Access the parameter via the params object in the GET handler.
```typescript
// routes/users/$id.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/users/$id')({
server: {
handlers: {
GET: async ({ params }) => {
const { id } = params
return new Response(`User ID: ${id}`)
},
},
},
})
// Visit /users/123 to see the response
// User ID: 123
```
--------------------------------
### TanStack Start Router Configuration and Solid.js Root Document
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-netlify
Configure the router with metadata and scripts, and define the main HTML shell using Solid.js components.
```tsx
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
scripts: [
{
src: '/customScript.js',
type: 'text/javascript',
},
],
}),
errorComponent: DefaultCatchBoundary,
notFoundComponent: () => ,
shellComponent: RootDocument,
})
function RootDocument({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Set up execution boundary functions in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/code-execution-patterns.md
Import and use createServerFn, createServerOnlyFn, createClientOnlyFn, and createIsomorphicFn to define where code executes. Server functions act as RPC calls, server-only functions crash on client, client-only functions crash on server, and isomorphic functions support different implementations per environment.
```tsx
import {
createServerFn,
createServerOnlyFn,
createClientOnlyFn,
createIsomorphicFn,
} from '@tanstack/solid-start'
// Server function (RPC call)
const getUsers = createServerFn().handler(async () => {
return await db.users.findMany()
})
// Server-only utility (crashes on client)
const getSecret = createServerOnlyFn(() => process.env.API_SECRET)
// Client-only utility (crashes on server)
const saveToStorage = createClientOnlyFn((data: any) => {
localStorage.setItem('data', JSON.stringify(data))
})
// Different implementations per environment
const logger = createIsomorphicFn()
.server((msg) => console.log(`[SERVER]: ${msg}`))
.client((msg) => console.log(`[CLIENT]: ${msg}`))
```
--------------------------------
### Quick Start: Access Environment Variables in Server and Client
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Demonstrates accessing server-only variables with process.env in server functions and client-safe VITE_ prefixed variables with import.meta.env in client components.
```typescript
// Server function - can access any environment variable
const getUser = createServerFn().handler(async () => {
const db = await connect(process.env.DATABASE_URL) // ✅ Server-only
return db.user.findFirst()
})
// Client component - only VITE_ prefixed variables
export function AppHeader() {
return
{import.meta.env.VITE_APP_NAME}
// ✅ Client-safe
}
```
--------------------------------
### Example .env.local File for Local Overrides
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
The .env.local file is used for local development overrides and sensitive keys, and should be added to .gitignore.
```bash
# Override for local development
DATABASE_URL=postgresql://user:password@localhost:5432/myapp_local
STRIPE_SECRET_KEY=sk_test_...
JWT_SECRET=your-local-secret
```
--------------------------------
### Create a Markdown Blog Post
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Example of a markdown file with front matter (title, published, authors, description) and content, including an image and a JavaScript code block.
```markdown
##
title: Hello World
published: 2024-01-15
authors:
- Jane Doe
description: My first blog post
---

Welcome to my blog! This is my first post.
## Getting Started
Here's some content with **bold** and _italic_ text.
```javascript
console.log('Hello, world!')
```
```
--------------------------------
### Install Tailwind CSS v3 and Dependencies
Source: https://tanstack.com/start/latest/docs/framework/react/guide/tailwind-integration
Install Tailwind CSS version 3 with PostCSS and autoprefixer as dev dependencies, then generate configuration files.
```shell
npm install -D tailwindcss@3 postcss autoprefixer
```
```shell
npx tailwindcss init -p
```
--------------------------------
### Create Router Configuration in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Set up the router instance with routeTree and optional configuration like scrollRestoration. This file defines TanStack Router behavior within TanStack Start.
```tsx
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function getRouter() {
const router = createRouter({
routeTree,
scrollRestoration: true,
})
return router
}
```
--------------------------------
### Install srvx for FastResponse Optimization
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Install the srvx package to enable the FastResponse optimization for Node.js deployments using Nitro.
```bash
npm install srvx
```
--------------------------------
### Environment-Specific Isomorphic Logger in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Defines an isomorphic logger using `createIsomorphicFn` to provide different logging behaviors for server and client, and for development and production environments. It includes an example of how to use the logger within a `createServerFn` handler.
```tsx
// utils/logger.ts
import { createIsomorphicFn } from '@tanstack/react-start'
type LogLevel = 'debug' | 'info' | 'warn' | 'error'
const logger = createIsomorphicFn()
.server((level: LogLevel, message: string, data?: any) => {
const timestamp = new Date().toISOString()
if (process.env.NODE_ENV === 'development') {
// Development: Detailed console logging
console[level](`[${timestamp}] [${level.toUpperCase()}]`, message, data)
} else {
// Production: Structured JSON logging
console.log(
JSON.stringify({
timestamp,
level,
message,
data,
service: 'tanstack-start',
environment: process.env.NODE_ENV,
}),
)
}
})
.client((level: LogLevel, message: string, data?: any) => {
if (process.env.NODE_ENV === 'development') {
console[level](`[CLIENT] [${level.toUpperCase()}]`, message, data)
} else {
// Production: Send to analytics service
// analytics.track('client_log', { level, message, data })
}
})
// Usage anywhere in your app
export { logger }
// Example usage
const fetchUserData = createServerFn().handler(async ({ data: userId }) => {
logger('info', 'Fetching user data', { userId })
try {
const user = await db.users.findUnique({ where: { id: userId } })
logger('info', 'User data fetched successfully', { userId })
return user
} catch (error) {
logger('error', 'Failed to fetch user data', {
userId,
error: error.message,
})
throw error
}
})
```
--------------------------------
### Install TypeScript development dependencies
Source: https://tanstack.com/start/latest/docs/framework/solid/build-from-scratch.md
Install TypeScript and Node.js type definitions as development dependencies.
```shell
npm i -D typescript @types/node
```
--------------------------------
### Initialize new project directory with npm
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Create a new project directory and initialize it with npm to set up a basic package.json file.
```shell
mkdir myApp
cd myApp
npm init -y
```
--------------------------------
### TanStack Start Application Configuration and Root Document
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic
This snippet shows the main configuration object for a TanStack Start application, defining links, scripts, error boundaries, and the `RootDocument` component. It also includes the `RootDocument` component itself, which sets up the basic HTML structure and navigation.
```typescript
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
scripts: [
{
src: '/customScript.js',
type: 'text/javascript',
},
],
}),
errorComponent: DefaultCatchBoundary,
notFoundComponent: () => ,
shellComponent: RootDocument,
})
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Initialize Execution Boundaries in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/code-execution-patterns.md
Use specialized creation functions to define logic for server-only, client-only, or isomorphic execution.
```tsx
import {
createServerFn,
createServerOnlyFn,
createClientOnlyFn,
createIsomorphicFn,
} from '@tanstack/react-start'
// Server function (RPC call)
const getUsers = createServerFn().handler(async () => {
return await db.users.findMany()
})
// Server-only utility (crashes on client)
const getSecret = createServerOnlyFn(() => process.env.API_SECRET)
// Client-only utility (crashes on server)
const saveToStorage = createClientOnlyFn((data: any) => {
localStorage.setItem('data', JSON.stringify(data))
})
// Different implementations per environment
const logger = createIsomorphicFn()
.server((msg) => console.log(`[SERVER]: ${msg}`))
.client((msg) => console.log(`[CLIENT]: ${msg}`))
```
--------------------------------
### Install Vite React plugin
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Install the official Vite React plugin as a dev dependency. Alternatively, @vitejs/plugin-react-swc can be used.
```shell
npm i -D @vitejs/plugin-react
```
--------------------------------
### TypeScript configuration for TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Create a tsconfig.json with recommended compiler options for TanStack Start projects. Keep verbatimModuleSyntax disabled to prevent server bundles from leaking into client bundles.
```json
{
"compilerOptions": {
"jsx": "react-jsx",
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ES2022",
"skipLibCheck": true,
"strictNullChecks": true
}
}
```
--------------------------------
### Configure TanStack Start Root with Head Metadata and Shell Component
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic
Set up the root configuration for a TanStack Start application including favicon/manifest links, error boundary, not found component, and shell component. The head array defines metadata tags that will be injected into the document head.
```TypeScript
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
```
--------------------------------
### TanStack Start Application Root Configuration
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-react-query
This snippet shows the main configuration object for a TanStack Start application, including SEO metadata, external links, custom error and not-found components, and the `RootComponent` and `RootDocument` definitions for the application's layout and navigation.
```typescript
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Install vite-tsconfig-paths for Vite 7 and Earlier
Source: https://tanstack.com/start/latest/docs/framework/react/guide/path-aliases.md
Install the `vite-tsconfig-paths` plugin as a development dependency for projects using Vite 7 or older versions to enable path alias resolution.
```sh
npm install -D vite-tsconfig-paths
```
--------------------------------
### Create First Route with Server Functions in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/build-from-scratch.md
Set up a route file with server functions for reading and updating a count value stored in a file. Includes a loader that fetches initial data and a component with a button that triggers server-side updates and router invalidation.
```tsx
import * as fs from 'node:fs'
import { createFileRoute, useRouter } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'
const filePath = 'count.txt'
async function readCount() {
return parseInt(
await fs.promises.readFile(filePath, 'utf-8').catch(() => '0'),
)
}
const getCount = createServerFn({
method: 'GET',
}).handler(() => {
return readCount()
})
const updateCount = createServerFn({ method: 'POST' })
.inputValidator((d: number) => d)
.handler(async ({ data }) => {
const count = await readCount()
await fs.promises.writeFile(filePath, `${count + data}`)
})
export const Route = createFileRoute('/')({
component: Home,
loader: async () => await getCount(),
})
function Home() {
const router = useRouter()
const state = Route.useLoaderData()
return (
)
}
```
--------------------------------
### SolidJS Root Route with TanStack Start and Convex Auth
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-convex-better-auth
This snippet defines the root route for a SolidJS application using TanStack Start, integrating Convex for authentication and applying global styles. It sets up the document structure and provides the Convex context.
```typescript
///
import { HeadContent, Scripts, createRootRoute } from '@tanstack/solid-router'
import { HydrationScript, Suspense } from 'solid-js/web'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import type * as Solid from 'solid-js'
import appCss from '~/styles/app.css?url'
import AppConvexProvider from '~/providers/convex'
import { fetchAuth } from '~/library/server'
export const Route = createRootRoute({
head: () => ({
links: [{ rel: 'stylesheet', href: appCss }],
}),
beforeLoad: async () => {
const { session, token } = await fetchAuth()
return { session, token }
},
shellComponent: RootDocument,
})
function RootDocument(props: { children: Solid.JSX.Element }) {
return (
{props.children}
)
}
```
--------------------------------
### Install Cloudflare Vite Plugin and Wrangler
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Install required dependencies for Cloudflare Workers deployment using pnpm package manager.
```bash
pnpm add -D @cloudflare/vite-plugin wrangler
```
--------------------------------
### Adapt Home Page to TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Convert Next.js default export component to TanStack Start route definition using createFileRoute. Replace the default export with a Route object and wrap the component function.
```tsx
import { createFileRoute } from '@tanstack/react-router' // [!code ++]
- export default function Home() { // [!code --]
+ export const Route = createFileRoute('/')({ // [!code ++]
+ component: Home, // [!code ++]
+ }) // [!code ++]
+ function Home() { // [!code ++]
return (
Next.js TanStack Start
Docs
)
}
```
--------------------------------
### Initialize Root Route with QueryClient Context in Solid
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-solid-query
Use createRootRouteWithContext to provide a QueryClient to the application. This setup includes global SEO tags, stylesheet links, and the main HTML document structure.
```typescript
///
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRouteWithContext,
} from '@tanstack/solid-router'
import { SolidQueryDevtools } from '@tanstack/solid-query-devtools'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { HydrationScript } from 'solid-js/web'
import type * as Solid from 'solid-js'
import type { QueryClient } from '@tanstack/solid-query'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRouteWithContext<{
queryClient: QueryClient
}>()({
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Generate Dynamic robots.txt Using a Server Route (TanStack Start)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
Create a dynamic 'robots.txt' file using a server route for complex scenarios, such as environment-specific rules, by returning plain text.
```ts
// src/routes/robots[.]txt.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/robots.txt')({
server: {
handlers: {
GET: async () => {
const robots = `User-agent: *
Allow: /
Sitemap: https://myapp.com/sitemap.xml`
return new Response(robots, {
headers: {
'Content-Type': 'text/plain',
},
})
},
},
},
})
```
--------------------------------
### Define a Root Route with Server Functions (TanStack Start)
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
This snippet defines the root route ('/') using `createFileRoute` and integrates server functions (`createServerFn`) for reading and updating a count, showcasing data loading and mutation within a TanStack Start application.
```tsx
import * as fs from 'node:fs'
import { createFileRoute, useRouter } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'
const filePath = 'count.txt'
async function readCount() {
return parseInt(
await fs.promises.readFile(filePath, 'utf-8').catch(() => '0'),
)
}
const getCount = createServerFn({
method: 'GET',
}).handler(() => {
return readCount()
})
const updateCount = createServerFn({ method: 'POST' })
.inputValidator((d: number) => d)
.handler(async ({ data }) => {
const count = await readCount()
await fs.promises.writeFile(filePath, `${count + data}`)
})
export const Route = createFileRoute('/')({
component: Home,
loader: async () => await getCount(),
})
function Home() {
const router = useRouter()
const state = Route.useLoaderData()
return (
)
}
```
--------------------------------
### Enable Automatic Server-Side Rendering (TanStack Start)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
TanStack Start automatically enables SSR for routes by default, ensuring fully rendered HTML for SEO without explicit configuration.
```tsx
export const Route = createFileRoute('/about')({
component: AboutPage,
})
```
--------------------------------
### Install Vite RSC Plugin
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Install the @vitejs/plugin-rsc package using your preferred package manager. Required for Server Components support.
```bash
npm install -D @vitejs/plugin-rsc
# or
pnpm add -D @vitejs/plugin-rsc
# or
yarn add -D @vitejs/plugin-rsc
# or
bun add -D @vitejs/plugin-rsc
```
--------------------------------
### Add Organization and Website Schema in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
This snippet demonstrates how to add 'Organization' and 'WebSite' Schema.org markup to the root route of a TanStack Start application for site-wide context. It includes meta tags and a script for JSON-LD.
```tsx
// src/routes/__root.tsx
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
],
scripts: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'My App',
url: 'https://myapp.com',
publisher: {
'@type': 'Organization',
name: 'My Company',
url: 'https://myapp.com',
logo: 'https://myapp.com/logo.png',
sameAs: [
'https://twitter.com/mycompany',
'https://github.com/mycompany',
],
},
}),
},
],
}),
component: RootComponent,
})
```
--------------------------------
### Example .env.production File for Production Overrides
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
The .env.production file contains variables specific to the production environment, overriding defaults or development settings.
```bash
# Production overrides
VITE_API_URL=https://api.myapp.com
DATABASE_POOL_SIZE=20
```
--------------------------------
### Create Type-Safe Server Entry Point with createServerEntry
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-entry-point.md
This example demonstrates how to create a type-safe server entry point using createServerEntry from @tanstack/solid-start/server-entry, wrapping the default handler.
```tsx
// src/server.ts
import handler, { createServerEntry } from '@tanstack/solid-start/server-entry'
export default createServerEntry({
fetch(request) {
return handler.fetch(request)
}
})
```
--------------------------------
### Configure Root Head Metadata and Scripts in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-cloudflare
Set up favicon links, manifest, and custom scripts in the root configuration. These head elements are applied globally to all pages.
```TypeScript
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
scripts: [
{
src: '/customScript.js',
type: 'text/javascript',
},
],
```
--------------------------------
### TanStack Start Data Fetching Sequence Diagram
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/fetching-external-api
Visualizes the interaction between the user, router, server-side loader, and external API during navigation.
```mermaid
sequenceDiagram
autonumber
actor U as User
participant R as Router (TanStack Start)
participant L as Route Loader (/fetch-movies)
participant A as External API (TMDB)
participant V as MoviesPage (UI)
U->>R: Navigate to /fetch-movies
R->>L: Invoke loader (server-side)
L->>A: GET /movie/popular\nAuthorization: Bearer
A-->>L: JSON TMDBResponse
alt response.ok
L-->>R: { movies, error: null }
R->>V: Render SSR with movies
V-->>U: HTML with movie grid
else non-ok / error
L-->>R: { movies: [], error: "Failed to load movies" }
R->>V: Render SSR with error alert
V-->>U: HTML with error state
end
note over L,V: Loader validates response.ok,\nreturns data or error for initial render
```
--------------------------------
### Configure Static Prerendering in Vite (TanStack Start)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
Enable static prerendering and link crawling in your 'vite.config.ts' to generate HTML at build time for improved performance and crawlability.
```ts
// vite.config.ts
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
export default defineConfig({
plugins: [
tanstackStart({
prerender: {
enabled: true,
crawlLinks: true,
},
}),
],
})
```
--------------------------------
### Install Tailwind CSS v3 and Dependencies
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/tailwind-integration.md
Install Tailwind CSS version 3 with PostCSS and autoprefixer as dev dependencies for legacy projects.
```shell
npm install -D tailwindcss@3 postcss autoprefixer
```
--------------------------------
### Remove Next.js and Configuration
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Uninstall Next.js and delete its associated configuration files to prepare for the new setup.
```shell
npm uninstall @tailwindcss/postcss next
rm postcss.config.* next.config.*
```
--------------------------------
### Quick Start: Define Environment Variables in .env
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Define environment variables in a .env file. Variables prefixed with VITE_ are exposed to the client, while others are server-only.
```bash
# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
VITE_APP_NAME=My TanStack Start App
```
--------------------------------
### Create a Static sitemap.xml File
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
Place a static 'sitemap.xml' file in your 'public' directory for simple sites with a known, unchanging structure.
```xml
https://myapp.com/daily1.0https://myapp.com/aboutmonthly
```
--------------------------------
### Implement Root Route Authentication in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-auth
Uses beforeLoad to fetch user data via a server function and provides the user context to the entire application.
```tsx
///
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import { createServerFn } from '@tanstack/react-start'
import * as React from 'react'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary.js'
import { NotFound } from '~/components/NotFound.js'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo.js'
import { useAppSession } from '~/utils/session.js'
const fetchUser = createServerFn({ method: 'GET' }).handler(async () => {
// We need to auth on the server so we have access to secure cookies
const session = await useAppSession()
if (!session.data.userEmail) {
return null
}
return {
email: session.data.userEmail,
}
})
export const Route = createRootRoute({
beforeLoad: async () => {
const user = await fetchUser()
return {
user,
}
},
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
const { user } = Route.useRouteContext()
return (
Home
{' '}
Posts
{user ? (
<>
{user.email}
Logout
>
) : (
Login
)}
{children}
)
}
```
--------------------------------
### Generate Dynamic Sitemap Using a Server Route (TanStack Start)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
Create a dynamic sitemap for content that changes frequently or cannot be discovered at build time by defining a server route that returns XML.
```ts
// src/routes/sitemap[.]xml.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/sitemap.xml')({
server: {
handlers: {
GET: async () => {
const posts = await fetchAllPosts()
const sitemap = `
https://myapp.com/daily1.0
${posts
.map(
(post) => `
https://myapp.com/posts/${post.id}${post.updatedAt}weekly`,
)
.join('')}
`
return new Response(sitemap, {
headers: {
'Content-Type': 'application/xml',
},
})
},
},
},
})
```
--------------------------------
### Root Route with Context and Head Configuration
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-react-query
Creates a root route with QueryClient context, configures head metadata (charset, viewport, SEO), favicon links, and error/not-found handlers. Use this as the entry point for your TanStack Start application.
```TypeScript
///
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRouteWithContext,
} from '@tanstack/react-router'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import * as React from 'react'
import type { QueryClient } from '@tanstack/react-query'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRouteWithContext<{
queryClient: QueryClient
}>()({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
```
--------------------------------
### Configure Global Fetch via createStart in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Define a default custom fetch for all server functions by providing serverFns.fetch in createStart. This global fetch has the lowest priority and is overridden by middleware or call-site implementations.
```tsx
// src/start.ts
import { createStart } from '@tanstack/react-start'
import type { CustomFetch } from '@tanstack/react-start'
const globalFetch: CustomFetch = async (url, init) => {
console.log('Global fetch:', url)
// Add retry logic, telemetry, etc.
return fetch(url, init)
}
export const startInstance = createStart(() => {
return {
serverFns: {
fetch: globalFetch,
},
}
})
```
--------------------------------
### Example of Importing with Path Alias
Source: https://tanstack.com/start/latest/docs/framework/react/guide/path-aliases.md
This snippet demonstrates how to use the `~` prefix defined in `tsconfig.json` to import modules, replacing long relative paths with a concise alias.
```ts
// app/routes/posts/$postId/edit.tsx
import { Input } from '~/components/ui/input'
// instead of
import { Input } from '../../../components/ui/input'
```
--------------------------------
### Define basic meta tags in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
Use the head property within createFileRoute to set static page titles and meta descriptions.
```tsx
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
head: () => ({
meta: [
{ title: 'My App - Home' },
{
name: 'description',
content: 'Welcome to My App, a platform for...',
},
],
}),
component: HomePage,
})
```
--------------------------------
### Create HTTP Response with Custom Headers in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
Returns an HTTP response with plain text content type and custom headers. This pattern is commonly used in TanStack Start server handlers to serve content with specific MIME types and metadata. The Response object wraps content and header configuration for HTTP responses.
```JavaScript
return new Response(content, {
headers: {
'Content-Type': 'text/plain',
},
})
```
--------------------------------
### Create Root Route with Head Metadata and Navigation
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic
Sets up the root route with head configuration including meta tags, links, and scripts. Defines a shell component with navigation links and error handling. Use this as the entry point for your TanStack Start application.
```TypeScript
///
import {
HeadContent,
Link,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import * as React from 'react'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
scripts: [
{
src: '/customScript.js',
type: 'text/javascript',
},
],
}),
errorComponent: DefaultCatchBoundary,
notFoundComponent: () => ,
shellComponent: RootDocument,
})
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Install Cloudflare Vite plugin
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Add the Cloudflare Vite plugin as a development dependency to enable Cloudflare-specific build optimizations.
```bash
pnpm install @cloudflare/vite-plugin -D
```
--------------------------------
### Combine Route-Level and Handler-Specific Middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Demonstrates how to use both route-level middleware (e.g., `authMiddleware`) and handler-specific middleware (e.g., `validationMiddleware`) within a single server route.
```tsx
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
middleware: [authMiddleware], // Runs first for all handlers
handlers: ({ createHandlers }) =>
createHandlers({
GET: async ({ request }) => {
return new Response('Hello, World!')
},
POST: {
middleware: [validationMiddleware], // Runs after authMiddleware, only for POST
handler: async ({ request }) => {
const body = await request.json()
return new Response(`Hello, ${body.name}!`)
}
}
})
}
})
```
--------------------------------
### Validate Required Environment Variables at Startup
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Provides a script to ensure that essential server-side and client-side environment variables are present when the application starts.
```typescript
// src/config/validation.ts
const requiredServerEnv = ['DATABASE_URL', 'JWT_SECRET'] as const
const requiredClientEnv = ['VITE_APP_NAME', 'VITE_API_URL'] as const
// Validate on server startup
for (const key of requiredServerEnv) {
if (!process.env[key]) {
throw new Error(`Missing required environment variable: ${key}`)
}
}
// Validate client environment at build time
for (const key of requiredClientEnv) {
if (!import.meta.env[key]) {
throw new Error(`Missing required environment variable: ${key}`)
}
}
```
--------------------------------
### Database Configuration with Environment Variables
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Demonstrates how to configure a database connection in a server function, using environment variables for connection details, max connections, and SSL settings.
```typescript
// src/lib/database.ts
import { createServerFn } from '@tanstack/react-start'
const getDatabaseConnection = createServerFn().handler(async () => {
const config = {
url: process.env.DATABASE_URL,
maxConnections: parseInt(process.env.DB_MAX_CONNECTIONS || '10'),
ssl: process.env.NODE_ENV === 'production',
}
return createConnection(config)
})
```
--------------------------------
### Root Route Configuration in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-convex-trellaux
This snippet defines the root route for a TanStack Start application, including global head content (meta, links), error handling, and the main layout structure. It uses `createRootRouteWithContext` to provide a `queryClient` to the route context.
```tsx
///
import { ReactQueryDevtools } from '@tanstack/react-query-devtools/production'
import {
Link,
Outlet,
createRootRouteWithContext,
useRouterState,
HeadContent,
Scripts,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import * as React from 'react'
import { Toaster } from 'react-hot-toast'
import type { QueryClient } from '@tanstack/react-query'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { IconLink } from '~/components/IconLink'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
import { Loader } from '~/components/Loader'
export const Route = createRootRouteWithContext<{
queryClient: QueryClient
}>()({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Trellaux
a TanStack Demo
{/*
*/}
{children}
)
}
```
--------------------------------
### TanStack Start Response Handler
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
A code fragment demonstrating a response handler that returns plain text content.
```javascript
`\n\n return new Response(content, {\n headers: {\n 'Content-Type': 'text/plain',\n },\n })\n },\n },\n },\n})
```
--------------------------------
### Root Route and Session Management in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-authjs
Defines the root route context, fetches the user session on the server, and sets up the main application layout with navigation. Uses createServerFn to securely fetch session data on the server side.
```tsx
///
import type { AuthSession } from 'start-authjs'
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRouteWithContext,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { createServerFn } from '@tanstack/solid-start'
import { getRequest } from '@tanstack/solid-start/server'
import { HydrationScript } from 'solid-js/web'
import { Show } from 'solid-js'
import { getSession } from 'start-authjs'
import type { JSX } from 'solid-js'
import { authConfig } from '~/utils/auth'
import appCss from '~/styles/app.css?url'
interface RouterContext {
session: AuthSession | null
}
const fetchSession = createServerFn({ method: 'GET' }).handler(async () => {
const request = getRequest()
const session = await getSession(request, authConfig)
return session
})
export const Route = createRootRouteWithContext()({
beforeLoad: async () => {
const session = await fetchSession()
return {
session,
}
},
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Auth Example',
},
],
links: [{ rel: 'stylesheet', href: appCss }],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: JSX.Element }) {
return (
{children}
)
}
function NavBar() {
const routeContext = Route.useRouteContext()
return (
)
}
```
```tsx
///
import type { AuthSession } from 'start-authjs'
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRouteWithContext,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { createServerFn } from '@tanstack/solid-start'
import { getRequest } from '@tanstack/solid-start/server'
import { HydrationScript } from 'solid-js/web'
import { Show } from 'solid-js'
import { getSession } from 'start-authjs'
import type { JSX } from 'solid-js'
import { authConfig } from '~/utils/auth'
import appCss from '~/styles/app.css?url'
interface RouterContext {
session: AuthSession | null
}
const fetchSession = createServerFn({ method: 'GET' }).handler(async () => {
const request = getRequest()
const session = await getSession(request, authConfig)
return session
})
export const Route = createRootRouteWithContext()({
beforeLoad: async () => {
const session = await fetchSession()
return {
session,
}
},
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Auth Example',
},
],
links: [{ rel: 'stylesheet', href: appCss }],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: JSX.Element }) {
return (
```
--------------------------------
### Use alternative package managers
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Use this if you prefer yarn or bun over npm for package management.
```bash
# or yarn, bun, etc.
```
--------------------------------
### SolidJS TanStack Router Root Route Head Configuration (Truncated)
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-cloudflare
A partial example showing the initial head configuration within the `createRootRoute` definition, including charset, viewport, SEO, and stylesheet links.
```typescript
///
import {
HeadContent,
Link,
Scripts,
createRootRoute,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { HydrationScript } from 'solid-js/web'
import type * as Solid from 'solid-js'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
```
--------------------------------
### Deploy to Cloudflare Workers
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Deploy the built TanStack Start application to Cloudflare Workers using the deploy script.
```bash
pnpm run deploy
```
--------------------------------
### Apply New Relic Middleware to TanStack Start Instance (TypeScript)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Integrates the New Relic transaction middleware into the TanStack Start application's request middleware chain.
```ts
// start.ts
import { createStart } from '@tanstack/react-start'
import { nrTransactionMiddleware } from './newrelic-middleware'
export const startInstance = createStart(() => {
return {
requestMiddleware: [nrTransactionMiddleware],
}
})
```
--------------------------------
### Root Route Loader with Authentication Setup
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-workos
Fetches authentication state and sign-in URL on the server to pass to the client without exposing sensitive tokens. Use this to prevent authentication loading flicker by providing initialAuth to AuthKitProvider.
```TypeScript
// getAuthAction() returns auth state without accessToken, safe for client
// Pass to AuthKitProvider as initialAuth to avoid loading flicker
const auth = await getAuthAction();
const url = await getSignInUrl();
return {
auth,
url,
};
```
--------------------------------
### Root Route Configuration with WorkOS AuthKit in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-workos
Defines the root route for a TanStack Start application, integrating WorkOS AuthKit for authentication state management and sign-in URL retrieval. It sets up global head content, loads initial authentication data, and renders the main application layout.
```typescript
import { Box, Button, Card, Container, Flex, Theme } from '@radix-ui/themes';
import { HeadContent, Link, Outlet, Scripts, createRootRoute } from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
import { Suspense } from 'react';
import { getSignInUrl } from '@workos/authkit-tanstack-react-start';
import { AuthKitProvider, getAuthAction } from '@workos/authkit-tanstack-react-start/client';
import Footer from '../components/footer';
import SignInButton from '../components/sign-in-button';
import appCssUrl from '../app.css?url';
import type { ReactNode } from 'react';
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'AuthKit Example in TanStack Start',
},
],
links: [{ rel: 'stylesheet', href: appCssUrl }],
}),
loader: async () => {
// getAuthAction() returns auth state without accessToken, safe for client
// Pass to AuthKitProvider as initialAuth to avoid loading flicker
const auth = await getAuthAction();
const url = await getSignInUrl();
return {
auth,
url,
};
},
component: RootComponent,
notFoundComponent: () =>
}>
);
}
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
return (
{children}
);
}
```
--------------------------------
### Create Machine-Readable Product List API Endpoint with Schema.org
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
This snippet demonstrates creating a server-side API endpoint in TanStack Start that returns a JSON response formatted with 'ItemList' and 'Product' Schema.org markup. This allows AI systems and developers to consume product data directly.
```ts
// src/routes/api/products.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/api/products')({
server: {
handlers: {
GET: async ({ request }) => {
const url = new URL(request.url)
const category = url.searchParams.get('category')
const products = await fetchProducts({ category })
return Response.json({
'@context': 'https://schema.org',
'@type': 'ItemList',
itemListElement: products.map((product, index) => ({
'@type': 'ListItem',
position: index + 1,
item: {
'@type': 'Product',
name: product.name,
description: product.description,
url: `https://myapp.com/products/${product.id}`,
},
})),
})
},
},
},
})
```
--------------------------------
### Configure global server function middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Add middleware to the functionMiddleware array in src/start.ts to apply it to every server function in the application.
```tsx
// src/start.ts
import { createStart } from '@tanstack/solid-start'
import { loggingMiddleware } from './middleware'
export const startInstance = createStart(() => {
return {
functionMiddleware: [loggingMiddleware],
}
})
```
--------------------------------
### Progressive Enhancement with TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
This component demonstrates how to build a search form that works without JavaScript and enhances with client-side functionality using ClientOnly.
```tsx
function SearchForm() {
const [query, setQuery] = useState('')
return (
)
}
```
--------------------------------
### Default Client Hydration in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/client-entry-point.md
Use this to manually initialize hydration and client-side routing using the hydrateStart utility.
```tsx
// src/client.tsx
import { hydrate } from 'solid-js/web'
import { StartClient, hydrateStart } from '@tanstack/solid-start/client'
hydrateStart().then((router) => {
hydrate(() => , document)
})
```
--------------------------------
### Clone Starter Template
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Command to clone a basic Next.js application to use as a reference for the migration process.
```shell
npx gitpick nrjdalal/awesome-templates/tree/main/next.js-apps/next.js-start next.js-start-er
```
--------------------------------
### Progressing Middleware Chain with next() in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Illustrates the use of the 'next()' function within a middleware's '.server()' method to execute the subsequent middleware in the chain and access its result.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().server(async ({ next }) => {
const result = await next() // <-- This will execute the next middleware in the chain
return result
})
```
--------------------------------
### Define a POST server route and integrate with a SolidJS component
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
This example demonstrates defining a POST server route in the same file as a SolidJS component. The component interacts with the server route to send JSON data and display the response, showcasing a full-stack interaction.
```tsx
// routes/hello.tsx
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
POST: async ({ request }) => {
const body = await request.json()
return new Response(JSON.stringify({ message: `Hello, ${body.name}!` }))
}
}
},
component: HelloComponent
})
function HelloComponent() {
const [reply, setReply] = createSignal('')
return (
)
}
```
--------------------------------
### Migrate Root Layout to __root.tsx
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Convert the Next.js layout.tsx to a TanStack Start root route using createRootRoute and HeadContent.
```tsx
- import type { Metadata } from "next" // [!code --]
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from "@tanstack/react-router"
import appCss from "./globals.css?url"
- export const metadata: Metadata = { // [!code --]
- title: "Create Next App", // [!code --]
- description: "Generated by create next app", // [!code --]
- } // [!code --]
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: "utf-8" },
{
name: "viewport",
content: "width=device-width, initial-scale=1",
},
{ title: "TanStack Start Starter" }
],
links: [
{
rel: 'stylesheet',
href: appCss,
},
],
}),
component: RootLayout,
})
- export default function RootLayout({ // [!code --]
- children, // [!code --]
- }: Readonly<{ // [!code --]
- children: React.ReactNode // [!code --]
- }>) { // [!code --]
- return ( // [!code --]
- // [!code --]
- {children} // [!code --]
- // [!code --]
- ) // [!code --]
- } // [!code --]
function RootLayout() {
return (
)
}
```
--------------------------------
### Create root application component
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Set up src/routes/__root.tsx as the entry point for all routes. This file wraps all other routes and defines the HTML document structure, metadata, and scripts.
```typescript
// src/routes/__root.tsx
///
import type { ReactNode } from 'react'
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from '@tanstack/react-router'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Starter',
},
],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
return (
{children}
)
}
```
--------------------------------
### Integrate New Relic with TanStack Start SSR Handler (TypeScript/React)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Imports New Relic and integrates it into the TanStack Start server handler to set controller names and add custom attributes based on route information.
```tsx
// server.tsx
import newrelic from 'newrelic' // Make sure this is the first import
import {
createStartHandler,
defaultStreamHandler,
defineHandlerCallback,
} from '@tanstack/react-start/server'
import type { ServerEntry } from '@tanstack/react-start/server-entry'
const customHandler = defineHandlerCallback(async (ctx) => {
// We do this so that transactions are grouped under the route ID instead of unique URLs
const matches = ctx.router?.state?.matches ?? []
const leaf = matches[matches.length - 1]
const routeId = leaf?.routeId ?? new URL(ctx.request.url).pathname
newrelic.setControllerName(routeId, ctx.request.method ?? 'GET')
newrelic.addCustomAttributes({
'route.id': routeId,
'http.method': ctx.request.method,
'http.path': new URL(ctx.request.url).pathname,
// Any other custom attributes you want to add
})
return defaultStreamHandler(ctx)
})
export default {
fetch(request) {
const handler = createStartHandler(customHandler)
return handler(request)
},
} satisfies ServerEntry
```
--------------------------------
### Define Root Document Component with Navigation in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-cloudflare
Create the shell component that wraps the entire application with HTML structure, hydration script, head content, and navigation links with active state styling.
```TypeScript
function RootDocument({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### MoviesPage Component with TanStack Start Loader
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/fetching-external-api.md
This component consumes data fetched by a TanStack Start route loader, displaying a grid of movies or an error message. It uses Route.useLoaderData() to access the fetched data.
```tsx
// MoviesPage component
const MoviesPage = () => {
const { movies, error } = Route.useLoaderData()
return (
Popular Movies
{error && (
{error}
)}
{movies.length > 0 ? (
{movies.slice(0, 12).map((movie) => (
))}
) : (
!error && (
Loading movies...
)
)}
)
}
```
--------------------------------
### Add Authoritative Attribution to Post Pages in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
This snippet shows how to include author information and publication details in the 'head' section of a TanStack Start route. These meta tags provide authority signals that AI systems consider.
```tsx
export const Route = createFileRoute('/posts/$postId')({
head: ({ loaderData }) => ({
meta: [
{ title: loaderData.post.title },
{ name: 'author', content: loaderData.post.author.name },
{
property: 'article:author',
content: loaderData.post.author.profileUrl,
},
{
property: 'article:published_time',
content: loaderData.post.publishedAt,
},
],
}),
component: PostPage,
})
```
--------------------------------
### Configure global request middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Define global middleware in src/start.ts using createStart to run logic before every request, including SSR and server routes. This file must be created manually if it does not exist in your template.
```tsx
// src/start.ts
import { createStart, createMiddleware } from '@tanstack/solid-start'
const myGlobalMiddleware = createMiddleware().server(() => {
//...
})
export const startInstance = createStart(() => {
return {
requestMiddleware: [myGlobalMiddleware],
}
})
```
--------------------------------
### Basic Meta Tags in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/seo.md
Set page title and meta description using the head property on routes. This is the primary tool for basic SEO configuration.
```tsx
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/')({
head: () => ({
meta: [
{ title: 'My App - Home' },
{
name: 'description',
content: 'Welcome to My App, a platform for...',
},
],
}),
component: HomePage,
})
```
--------------------------------
### Configure SPA prerendering in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/spa-mode
Override default shell generation settings such as output path, link crawling, and retry logic within the Vite configuration.
```tsx
// vite.config.ts
export default defineConfig({
plugins: [
tanstackStart({
spa: {
prerender: {
outputPath: '/custom-shell',
crawlLinks: true,
retryCount: 3,
},
},
}),
],
})
```
--------------------------------
### Configure Built-in Sitemap Generation in Vite (TanStack Start)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
Enable automatic sitemap generation by configuring the 'sitemap' option in 'vite.config.ts', alongside prerendering with link crawling, to discover all linkable pages.
```ts
// vite.config.ts
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
export default defineConfig({
plugins: [
tanstackStart({
prerender: {
enabled: true,
crawlLinks: true, // Discovers all linkable pages
},
sitemap: {
enabled: true,
host: 'https://myapp.com',
},
}),
],
})
```
--------------------------------
### Return JSON Response with Manual Headers in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Return JSON by manually serializing with JSON.stringify and setting the Content-Type header to application/json.
```typescript
// routes/hello.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return new Response(JSON.stringify({ message: 'Hello, World!' }), {
headers: {
'Content-Type': 'application/json',
},
})
},
},
},
})
// Visit /hello to see the response
// {"message":"Hello, World!"}
```
--------------------------------
### Create root application component
Source: https://tanstack.com/start/latest/docs/framework/solid/build-from-scratch.md
Set up the root route component that serves as the entry point for all other routes. This wraps all routes and provides the HTML document structure with hydration support.
```typescript
// src/routes/__root.tsx
///
import * as Solid from 'solid-js'
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from '@tanstack/solid-router'
import { HydrationScript } from 'solid-js/web'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Starter',
},
],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: Readonly<{ children: Solid.JSX.Element }>) {
return (
{children}
)
}
```
--------------------------------
### SSR inheritance behavior example 1
Source: https://tanstack.com/start/latest/docs/framework/react/guide/selective-ssr.md
Demonstrates how child routes inherit SSR configuration and the restriction that inherited values can only become more restrictive.
```tsx
root { ssr: undefined }
posts { ssr: false }
$postId { ssr: true }
```
--------------------------------
### Quick Observability Tool Integration Pattern
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Generic pattern for integrating observability tools with TanStack Start. Initialize in the app entry point and wrap server functions with error capture middleware.
```typescript
// Initialize in app entry point
import { initObservabilityTool } from 'your-tool'
initObservabilityTool({
dsn: import.meta.env.VITE_TOOL_DSN,
environment: import.meta.env.NODE_ENV,
})
// Server function middleware
const observabilityMiddleware = createMiddleware().handler(async ({ next }) => {
return yourTool.withTracing('server-function', async () => {
try {
return await next()
} catch (error) {
yourTool.captureException(error)
throw error
}
})
})
```
--------------------------------
### Install uuid package for unique IDs
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/reading-writing-file
Adds the `uuid` package to the project dependencies, which is used for generating unique identifiers.
```bash
pnpm add uuid
```
--------------------------------
### Configure Route Loader Caching in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/start-vs-nextjs
Use staleTime and gcTime within createFileRoute to manage SWR-style caching for RSC payloads.
```tsx
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => fetchPost(params.postId),
staleTime: 10_000, // Fresh for 10 seconds
gcTime: 5 * 60_000, // Keep in memory for 5 minutes
})
```
--------------------------------
### Implement Product JSON-LD Schema in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
Defines structured Product data for e-commerce routes, including price, currency, and availability. This metadata helps AI assistants provide precise product information and recommendations.
```tsx
export const Route = createFileRoute('/products/$productId')({
loader: async ({ params }) => {
const product = await fetchProduct(params.productId)
return { product }
},
head: ({ loaderData }) => ({
meta: [{ title: loaderData.product.name }],
scripts: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: loaderData.product.name,
description: loaderData.product.description,
image: loaderData.product.images,
brand: {
'@type': 'Brand',
name: loaderData.product.brand,
},
offers: {
'@type': 'Offer',
price: loaderData.product.price,
priceCurrency: 'USD',
availability: loaderData.product.inStock
? 'https://schema.org/InStock'
: 'https://schema.org/OutOfStock',
},
aggregateRating: loaderData.product.rating
? {
'@type': 'AggregateRating',
ratingValue: loaderData.product.rating,
reviewCount: loaderData.product.reviewCount,
}
: undefined,
}),
},
],
}),
component: ProductPage,
})
```
--------------------------------
### Define Server Function with Middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
This snippet demonstrates how to apply middleware to a specific server function using `createServerFn`'s `middleware` property. It shows importing `createServerFn` and a custom `loggingMiddleware`.
```tsx
import { createServerFn } from '@tanstack/react-start'
import { loggingMiddleware } from './middleware'
const fn = createServerFn()
.middleware([loggingMiddleware])
.handler(async () => {
//...
})
```
--------------------------------
### Recommended file organization for server logic
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Structure your project to separate server function wrappers from internal server-only helpers and shared schemas.
```text
src/utils/
├── users.functions.ts # Server function wrappers (createServerFn)
├── users.server.ts # Server-only helpers (DB queries, internal logic)
└── schemas.ts # Shared validation schemas (client-safe)
```
--------------------------------
### Prefix asset URLs with a string in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/cdn-asset-urls.md
Prepends a string to every manifest asset URL. This is the simplest way to point assets to a CDN origin known at runtime.
```tsx
// src/server.ts
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/react-start/server'
import { createServerEntry } from '@tanstack/react-start/server-entry'
const handler = createStartHandler({
handler: defaultStreamHandler,
transformAssets: process.env.CDN_ORIGIN || '',
})
export default createServerEntry({ fetch: handler })
```
--------------------------------
### Configure TanStack Start Import Protection in Vite
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This snippet demonstrates how to set up import protection rules in your Vite configuration using the `tanstackStart` plugin. It shows how to block specific npm packages and files for client and server environments.
```ts
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
export default defineConfig({
plugins: [
tanstackStart({
importProtection: {
client: {
// Block specific npm packages from the client bundle
specifiers: ['@prisma/client', 'bcrypt'],
// Block files in a custom directory
files: ['**/db/**'],
},
server: {
// Block browser-only libraries from the server
specifiers: ['localforage'],
},
},
}),
],
})
```
--------------------------------
### Implement Authentication Logic with TanStack Start Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
This snippet defines server functions for user login, logout, and retrieving the current user. It uses `createServerFn` to handle server-side authentication logic securely, including credential verification, session updates, and redirects.
```tsx
import { createServerFn } from '@tanstack/react-start'
import { redirect } from '@tanstack/react-router'
// Login server function
export const loginFn = createServerFn({ method: 'POST' })
.inputValidator((data: { email: string; password: string }) => data)
.handler(async ({ data }) => {
// Verify credentials (replace with your auth logic)
const user = await authenticateUser(data.email, data.password)
if (!user) {
return { error: 'Invalid credentials' }
}
// Create session
const session = await useAppSession()
await session.update({
userId: user.id,
email: user.email,
})
// Redirect to protected area
throw redirect({ to: '/dashboard' })
})
// Logout server function
export const logoutFn = createServerFn({ method: 'POST' }).handler(async () => {
const session = await useAppSession()
await session.clear()
throw redirect({ to: '/' })
})
// Get current user
export const getCurrentUserFn = createServerFn({ method: 'GET' }).handler(
async () => {
const session = await useAppSession()
const userId = session.data.userId
if (!userId) {
return null
}
return await getUserById(userId)
},
)
```
--------------------------------
### createServerFn Handler Example (Server-side)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This snippet shows a `createServerFn` handler on the server, importing a server-only function `getUsers`. The compiler will replace this handler with a client RPC stub for the client build.
```ts
import { getUsers } from './db/queries.server'
import { createServerFn } from '@tanstack/react-start'
export const fetchUsers = createServerFn().handler(async () => {
return getUsers()
})
```
--------------------------------
### Configure Netlify Plugin in Vite Config
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Add the Netlify plugin to your vite.config.ts alongside the TanStack Start and React plugins.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import netlify from '@netlify/vite-plugin-tanstack-start' // ← add this
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
tanstackStart(),
netlify(), // ← add this (anywhere in the array is fine)
viteReact(),
],
})
```
--------------------------------
### Create a server function to read files using TanStack Start and Node.js
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/reading-writing-file.md
Use createServerFn to define server-side logic that reads from the filesystem. This function can be called directly from client-side components or loaders.
```tsx
// src/serverActions/jokesActions.ts
import { createServerFn } from '@tanstack/solid-start'
import * as fs from 'node:fs'
import type { JokesData } from '../types'
const JOKES_FILE = 'src/data/jokes.json'
export const getJokes = createServerFn({ method: 'GET' }).handler(async () => {
const jokes = await fs.promises.readFile(JOKES_FILE, 'utf-8')
return JSON.parse(jokes) as JokesData
})
```
--------------------------------
### Configure Authentication Provider with Server and Client Environment Variables
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-variables.md
Shows how to configure an authentication provider, separating server-only secrets from client-safe public keys using `process.env` and `import.meta.env.VITE_` respectively.
```typescript
// src/lib/auth.ts (Server)
export const authConfig = {
secret: process.env.AUTH_SECRET,
providers: {
auth0: {
domain: process.env.AUTH0_DOMAIN,
clientId: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET, // Server-only
}
}
}
```
```typescript
// src/components/AuthProvider.tsx (Client)
export function AuthProvider(props) {
return (
{props.children}
)
}
```
--------------------------------
### Combine Static Prerendering with ISR in Vite Config
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Configure TanStack Start plugin to prerender routes at build time and enable crawlLinks for automatic discovery. Prerendered pages are instantly available while ISR handles updates.
```tsx
// vite.config.ts
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
tanstackStart({
prerender: {
routes: ['/blog', '/blog/posts/*'],
crawlLinks: true,
},
}),
],
})
```
--------------------------------
### Set Cache Headers in TanStack Start Server Function
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Use context.response.headers.set within a server function to configure browser and CDN caching strategies.
```tsx
export const fetchDocs = createServerFn({ method: 'GET' })
.inputValidator((params: FetchDocsParams) => params)
.handler(async ({ data: { repo, branch, filePath }, context }) => {
// Set cache headers for CDN caching
context.response.headers.set(
'Cache-Control',
'public, max-age=0, must-revalidate',
)
context.response.headers.set(
'CDN-Cache-Control',
'max-age=300, stale-while-revalidate=300',
)
// ... fetch logic
})
```
--------------------------------
### Conservative to Aggressive Cache Timing Progression
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Start with shorter cache times to understand content update patterns, then increase gradually. Shows recommended progression from conservative to aggressive caching.
```typescript
// Start here
'Cache-Control': 'public, max-age=300, stale-while-revalidate=600'
// Then move to
'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400'
```
--------------------------------
### Specify HTTP methods for server functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Use the method property to define GET (default) or POST requests for server logic.
```tsx
import { createServerFn } from '@tanstack/react-start'
// GET request (default)
export const getData = createServerFn().handler(async () => {
return { message: 'Hello from server!' }
})
// POST request
export const saveData = createServerFn({ method: 'POST' }).handler(async () => {
// Server-only logic
return { success: true }
})
```
--------------------------------
### TypeScript Interface for Import Protection Options
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
Defines the structure and available properties for configuring import protection behavior in TanStack Start projects.
```typescript
interface ImportProtectionOptions {
enabled?: boolean
behavior?:
| 'error'
| 'mock'
| { dev?: 'error' | 'mock'; build?: 'error' | 'mock' }
log?: 'once' | 'always'
include?: Array
exclude?: Array
ignoreImporters?: Array
maxTraceDepth?: number
client?: {
specifiers?: Array
files?: Array
excludeFiles?: Array
}
server?: {
specifiers?: Array
files?: Array
excludeFiles?: Array
}
onViolation?:
(info: ViolationInfo) => boolean | void | Promise
}
```
--------------------------------
### Multiple Dynamic Path Parameters in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Create nested routes with multiple dynamic parameters using the $paramName convention. Both parameters are accessible via the params object.
```typescript
// routes/users/$id/posts/$postId.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/users/$id/posts/$postId')({
server: {
handlers: {
GET: async ({ params }) => {
const { id, postId } = params
return new Response(`User ID: ${id}, Post ID: ${postId}`)
},
},
},
})
// Visit /users/123/posts/456 to see the response
// User ID: 123, Post ID: 456
```
--------------------------------
### Configure Root Route with Material UI and Emotion
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-material-ui
Use this setup in your root route to initialize Material UI themes and Emotion cache. It includes the necessary providers for styling and layout consistency.
```tsx
///
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import {
HeadContent,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
import { CacheProvider } from '@emotion/react'
import { Container, CssBaseline, ThemeProvider } from '@mui/material'
import createCache from '@emotion/cache'
import fontsourceVariableRobotoCss from '@fontsource-variable/roboto?url'
import React from 'react'
import { theme } from '~/setup/theme'
import { Header } from '~/components/Header'
export const Route = createRootRoute({
head: () => ({
links: [{ rel: 'stylesheet', href: fontsourceVariableRobotoCss }],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function Providers({ children }: { children: React.ReactNode }) {
const emotionCache = createCache({ key: 'css' })
return (
{children}
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
{children}
)
```
```tsx
///
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import {
HeadContent,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
import { CacheProvider } from '@emotion/react'
import { Container, CssBaseline, ThemeProvider } from '@mui/material'
import createCache from '@emotion/cache'
import fontsourceVariableRobotoCss from '@fontsource-variable/roboto?url'
import React from 'react'
import { theme } from '~/setup/theme'
import { Header } from '~/components/Header'
export const Route = createRootRoute({
head: () => ({
links: [{ rel: 'stylesheet', href: fontsourceVariableRobotoCss }],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function Providers({ children }: { children: React.ReactNode }) {
const emotionCache = createCache({ key: 'css' })
return (
{children}
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
{children}
)
```
--------------------------------
### Wildcard/Splat Parameter in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Use a $ filename to create a wildcard route that captures remaining path segments. Access the captured path via the _splat parameter.
```typescript
// routes/file/$.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/file/$')({
server: {
handlers: {
GET: async ({ params }) => {
const { _splat } = params
return new Response(`File: ${_splat}`)
},
},
},
})
// Visit /file/hello.txt to see the response
// File: hello.txt
```
--------------------------------
### Unit test server authentication functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
Test server functions with vitest to verify valid credentials succeed and invalid credentials are rejected. Requires test database setup.
```tsx
// __tests__/auth.test.ts
import { describe, it, expect, beforeEach } from 'vitest'
import { loginFn } from '../server/auth'
describe('Authentication', () => {
beforeEach(async () => {
await setupTestDatabase()
})
it('should login with valid credentials', async () => {
const result = await loginFn({
data: { email: 'test@example.com', password: 'password123' },
})
expect(result.error).toBeUndefined()
expect(result.user).toBeDefined()
})
it('should reject invalid credentials', async () => {
const result = await loginFn({
data: { email: 'test@example.com', password: 'wrongpassword' },
})
expect(result.error).toBe('Invalid credentials')
})
})
```
--------------------------------
### Define Type-Safe Server Functions in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/start-vs-nextjs
Create server functions with Zod validation, middleware support, and full type inference for inputs and outputs.
```tsx
export const createPost = createServerFn({ method: 'POST' })
.validator(z.object({ title: z.string().min(1) }))
.middleware([authMiddleware])
.handler(async ({ data, context }) => {
// data is typed and validated
// context comes from middleware, also typed
return db.posts.create({ title: data.title })
})
```
--------------------------------
### Configure Global Request Middleware in src/start.ts
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Create src/start.ts and use createStart() with requestMiddleware array to run middleware for every request, including server routes, SSR, and server functions.
```typescript
// src/start.ts
import { createStart, createMiddleware } from '@tanstack/react-start'
const myGlobalMiddleware = createMiddleware().server(() => {
//...
})
export const startInstance = createStart(() => {
return {
requestMiddleware: [myGlobalMiddleware],
}
})
```
--------------------------------
### Access Server-Side Environment Variables in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-variables.md
Illustrates how server functions can securely access any environment variable using `process.env`, ensuring sensitive data remains server-only.
```typescript
import { createServerFn } from '@tanstack/solid-start'
// Database connection (server-only)
const connectToDatabase = createServerFn().handler(async () => {
const connectionString = process.env.DATABASE_URL // No prefix needed
const apiKey = process.env.EXTERNAL_API_SECRET // Stays on server
// These variables are never exposed to the client
return await database.connect(connectionString)
})
// Authentication (server-only)
const authenticateUser = createServerFn()
.inputValidator(z.object({ token: z.string() }))
.handler(async ({ data }) => {
const jwtSecret = process.env.JWT_SECRET // Server-only
return jwt.verify(data.token, jwtSecret)
})
```
--------------------------------
### Request/Response Logging Middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
This snippet illustrates how to create a middleware to log incoming requests and outgoing responses, including status codes and durations, and how to apply it to server routes.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const requestLogger = createMiddleware().handler(async ({ next }) => {
const startTime = Date.now()
const timestamp = new Date().toISOString()
console.log(`[${timestamp}] ${request.method} ${request.url} - Starting`)
try {
const response = await next()
const duration = Date.now() - startTime
console.log(
`[${timestamp}] ${request.method} ${request.url} - ${response.status} (${duration}ms)`,
)
return response
} catch (error) {
const duration = Date.now() - startTime
console.error(
`[${timestamp}] ${request.method} ${request.url} - Error (${duration}ms):`,
error,
)
throw error
}
})
// Apply to all server routes
export const Route = createFileRoute('/api/users')({
server: {
middleware: [requestLogger],
handlers: {
GET: async () => {
return Response.json({ users: await getUsers() })
},
},
},
})
```
--------------------------------
### Configure vite-tsconfig-paths Plugin for Vite 7 and Earlier
Source: https://tanstack.com/start/latest/docs/framework/react/guide/path-aliases.md
After installing the plugin, update your `vite.config.ts` to import and use `viteTsConfigPaths` within the `plugins` array, pointing it to your `tsconfig.json`.
```ts
// vite.config.ts
import { defineConfig } from 'vite'
import viteTsConfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [
// this is the plugin that enables path aliases
viteTsConfigPaths({
projects: ['./tsconfig.json'],
}),
],
})
```
--------------------------------
### TanStack Start Root Route Configuration
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-convex-trellaux
Defines the root route with context, SEO metadata, and the main document structure. It integrates TanStack Router, React Query Devtools, and global styles.
```tsx
///
import { ReactQueryDevtools } from '@tanstack/react-query-devtools/production'
import {
Link,
Outlet,
createRootRouteWithContext,
useRouterState,
HeadContent,
Scripts,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import * as React from 'react'
import { Toaster } from 'react-hot-toast'
import type { QueryClient } from '@tanstack/react-query'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { IconLink } from '~/components/IconLink'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
import { Loader } from '~/components/Loader'
export const Route = createRootRouteWithContext<{
queryClient: QueryClient
}>()({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Trellaux
a TanStack Demo
{/*
*/}
{children}
)
}
function LoadingIndicator() {
const isLoading = useRouterState({ select: (s) => s.isLoading })
return (
data)
.handler(async ({ data }) => {
// Verify credentials (replace with your auth logic)
const user = await authenticateUser(data.email, data.password)
if (!user) {
return { error: 'Invalid credentials' }
}
// Create session
const session = await useAppSession()
await session.update({
userId: user.id,
email: user.email,
})
// Redirect to protected area
throw redirect({ to: '/dashboard' })
})
// Logout server function
export const logoutFn = createServerFn({ method: 'POST' }).handler(async () => {
const session = await useAppSession()
await session.clear()
throw redirect({ to: '/' })
})
// Get current user
export const getCurrentUserFn = createServerFn({ method: 'GET' }).handler(
async () => {
const session = await useAppSession()
const userId = session.get('userId')
if (!userId) {
return null
}
return await getUserById(userId)
},
)
```
--------------------------------
### Integrate Content Collections Vite Plugin
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Add the `@content-collections/vite` plugin to your TanStack Start `app.config.ts` to enable content collection processing during development and build.
```tsx
// app.config.ts
import { defineConfig } from '@tanstack/react-start/config'
import contentCollections from '@content-collections/vite'
export default defineConfig({
vite: {
plugins: [contentCollections()],
},
})
```
--------------------------------
### Configure Root Route with Head and Error Handling
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-auth
Set up the root route with document head metadata, SEO configuration, error boundary, and not-found component. The head includes viewport settings, title, description, stylesheets, and favicon links.
```TypeScript
createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
```
--------------------------------
### Define a Dynamic Route with createFileRoute
Source: https://tanstack.com/start/latest/docs/framework/react/guide/routing.md
Example of defining a dynamic route (`/posts/:postId`) using `createFileRoute` in a TSX file. The path string is automatically managed by the router bundler plugin or CLI.
```tsx
// src/routes/posts/$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
component: PostComponent,
})
```
--------------------------------
### Apply Naming Conventions for Environment Variables
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Illustrates the recommended naming conventions for server-only (no prefix) and client-safe (`VITE_`) environment variables.
```bash
# ✅ Server-only (no prefix)
DATABASE_URL=postgresql://...
JWT_SECRET=super-secret-key
STRIPE_SECRET_KEY=sk_live_...
```
```bash
# ✅ Client-safe (VITE_ prefix)
VITE_APP_NAME=My App
VITE_API_URL=https://api.example.com
VITE_SENTRY_DSN=https://...
```
--------------------------------
### Configure Vite Plugin for Tailwind CSS v4
Source: https://tanstack.com/start/latest/docs/framework/react/guide/tailwind-integration
Add the @tailwindcss/vite plugin to your Vite configuration file alongside other TanStack Start plugins.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import tsConfigPaths from 'vite-tsconfig-paths'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import tailwindcss from '@tailwindcss/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
server: {
port: 3000,
},
plugins: [tsConfigPaths(), tanstackStart(), viteReact(), tailwindcss()],
})
```
--------------------------------
### Migrate Dynamic Route Parameters in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Replace Next.js async params destructuring with Route.useParams() hook. For catch-all routes, access parameters via the _splat property.
```tsx
- export default async function Page({ // [!code --]
- params, // [!code --]
- }: { // [!code --]
- params: Promise<{ slug: string }> // [!code --]
- }) { // [!code --]
+ export const Route = createFileRoute('/app/posts/$slug')({ // [!code ++]
+ component: Page, // [!code ++]
+ }) // [!code ++]
+ function Page() { // [!code ++]
- const { slug } = await params // [!code --]
+ const { slug } = Route.useParams() // [!code ++]
return
My Post: {slug}
}
```
--------------------------------
### Configure the TanStack Start Router
Source: https://tanstack.com/start/latest/docs/framework/react/guide/routing.md
This snippet defines the `getRouter` function in `src/router.tsx`, which initializes and returns a new TanStack Router instance. It's the central configuration point for your application's routing behavior.
```tsx
// src/router.tsx
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
// You must export a getRouter function that
// returns a new router instance each time
export function getRouter() {
const router = createRouter({
routeTree,
scrollRestoration: true,
})
return router
}
```
--------------------------------
### Access Client-Side Environment Variables in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-variables.md
Shows how client components can safely access public environment variables prefixed with `VITE_` using `import.meta.env`, while server-only variables remain undefined.
```typescript
// Client configuration
export function ApiProvider(props) {
const apiUrl = import.meta.env.VITE_API_URL // ✅ Public
const apiKey = import.meta.env.VITE_PUBLIC_KEY // ✅ Public
// This would be undefined (security feature):
// const secret = import.meta.env.DATABASE_URL // ❌ Undefined
return (
{props.children}
)
}
// Feature flags
export function FeatureGatedComponent() {
const enableNewFeature = import.meta.env.VITE_ENABLE_NEW_FEATURE === 'true'
if (!enableNewFeature) return null
return
}
```
--------------------------------
### Return JSON Response Using Response.json Helper in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Use the Response.json() helper to automatically set the Content-Type header and serialize the JSON object without manual configuration.
```typescript
// routes/hello.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return Response.json({ message: 'Hello, World!' })
},
},
},
})
// Visit /hello to see the response
// {"message":"Hello, World!"}
```
--------------------------------
### Root Route with AuthJS Session Context in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-authjs
Sets up the root route with typed context containing an AuthSession. Uses createServerFn to fetch the session server-side before route load, and provides it to all child routes via beforeLoad hook.
```TypeScript
///
import type { ReactNode } from 'react'
import type { AuthSession } from 'start-authjs'
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRouteWithContext,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import { createServerFn } from '@tanstack/react-start'
import { getRequest } from '@tanstack/react-start/server'
import { getSession } from 'start-authjs'
import { authConfig } from '~/utils/auth'
import appCss from '~/styles/app.css?url'
interface RouterContext {
session: AuthSession | null
}
const fetchSession = createServerFn({ method: 'GET' }).handler(async () => {
const request = getRequest()
const session = await getSession(request, authConfig)
return session
})
export const Route = createRootRouteWithContext()({
beforeLoad: async () => {
const session = await fetchSession()
return {
session,
}
},
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Auth Example',
},
],
links: [{ rel: 'stylesheet', href: appCss }],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: ReactNode }) {
return (
{children}
)
}
function NavBar() {
const routeContext = Route.useRouteContext()
return (
)
}
```
--------------------------------
### Initialize OpenTelemetry Node SDK
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Set up the Node SDK with service metadata and auto-instrumentations before importing your app. Must be called before app initialization to capture all telemetry.
```typescript
// instrumentation.ts - Initialize before your app
import { NodeSDK } from '@opentelemetry/sdk-node'
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'tanstack-start-app',
[SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',
}),
instrumentations: [getNodeAutoInstrumentations()],
})
// Initialize BEFORE importing your app
sdk.start()
```
--------------------------------
### Configuring Static `NODE_ENV` Replacement in TanStack Start (TypeScript)
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-variables.md
Configure the `staticNodeEnv` option within `tanstackStart` plugin in `vite.config.ts` to control whether `process.env.NODE_ENV` is statically replaced at build time. The default is `true`.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
export default defineConfig({
plugins: [
tanstackStart({
server: {
build: {
// Replace process.env.NODE_ENV at build time (default: true)
staticNodeEnv: true,
}
}
})
]
})
```
--------------------------------
### Define the Root Route Component in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/routing.md
This code block illustrates the `__root.tsx` file, which sets up the application's base HTML structure. It uses `Outlet` to render child routes and includes `HeadContent` and `Scripts` for proper document rendering.
```tsx
// src/routes/__root.tsx
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from '@tanstack/react-router'
import type { ReactNode } from 'react'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Starter',
},
],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
return (
{children}
)
}
```
--------------------------------
### Implement rate limiting for login attempts
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
Use in-memory rate limiting for development or small deployments; switch to Redis for production. This example limits login attempts to 5 per 15 minutes per IP.
```tsx
// Simple in-memory rate limiting (use Redis in production)
const loginAttempts = new Map()
export const rateLimitLogin = (ip: string): boolean => {
const now = Date.now()
const attempts = loginAttempts.get(ip)
if (!attempts || now > attempts.resetTime) {
loginAttempts.set(ip, { count: 1, resetTime: now + 15 * 60 * 1000 }) // 15 min
return true
}
if (attempts.count >= 5) {
return false // Too many attempts
}
attempts.count++
return true
}
```
--------------------------------
### Exclude Custom Paths and Node Modules from Client Bundle
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This example demonstrates how to extend the default `excludeFiles` list to include additional directories like `vendor` while still excluding `node_modules` for the client environment.
```ts
importProtection: {
client: {
excludeFiles: ['**/node_modules/**', '**/vendor/**'],
},
}
```
--------------------------------
### Configure TypeScript Path Aliases in tsconfig.json
Source: https://tanstack.com/start/latest/docs/framework/react/guide/path-aliases.md
Add this configuration to your project's `tsconfig.json` file to define path aliases. This example maps the `~/*` alias to the `./src/*` directory.
```json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"]
}
}
}
```
--------------------------------
### Define and Use Feature Flags in TanStack React Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Defines feature flags using environment variables and demonstrates their conditional rendering logic within a React component.
```typescript
// src/config/features.ts
export const featureFlags = {
enableNewDashboard: import.meta.env.VITE_ENABLE_NEW_DASHBOARD === 'true',
enableAnalytics: import.meta.env.VITE_ENABLE_ANALYTICS === 'true',
debugMode: import.meta.env.VITE_DEBUG_MODE === 'true',
}
```
```typescript
// Usage in components
export function Dashboard() {
if (featureFlags.enableNewDashboard) {
return
}
return
}
```
--------------------------------
### Route Protection with beforeLoad in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
Use beforeLoad to verify authentication and redirect users before a route is rendered. Data returned from beforeLoad is accessible to child routes via useRouteContext.
```tsx
// routes/_authed.tsx - Layout route for protected pages
import { createFileRoute, redirect } from '@tanstack/react-router'
import { getCurrentUserFn } from '../server/auth'
export const Route = createFileRoute('/_authed')({
beforeLoad: async ({ location }) => {
const user = await getCurrentUserFn()
if (!user) {
throw redirect({
to: '/login',
search: { redirect: location.href },
})
}
// Pass user to child routes
return { user }
},
})
```
```tsx
// routes/_authed/dashboard.tsx - Protected route
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/_authed/dashboard')({
component: DashboardComponent,
})
function DashboardComponent() {
const { user } = Route.useRouteContext()
return (
Welcome, {user.email}!
{/* Dashboard content */}
)
}
```
--------------------------------
### Apply middleware to all server route methods
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Pass a middleware array to the `middleware` property in the route's `server` configuration to apply middleware to all HTTP methods (GET, POST, etc.).
```tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
export const Route = createFileRoute('/foo')({
server: {
middleware: [loggingMiddleware],
handlers: {
GET: () => {
//...
},
POST: () => {
//...
},
},
},
})
```
--------------------------------
### Update Package.json Scripts for Cloudflare Deployment
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Modify npm scripts to remove Node.js server start command and add Cloudflare preview, deploy, and type generation commands.
```json
{
"scripts": {
"dev": "vite dev",
"build": "vite build && tsc --noEmit",
"preview": "vite preview",
"deploy": "npm run build && wrangler deploy",
"cf-typegen": "wrangler types"
}
}
```
--------------------------------
### Import Leak Example with Helper Function
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/import-protection.md
Demonstrates how a server-only import can leak into the client build when referenced in a helper function outside the server boundary. The `leakyHelper` function keeps the import alive.
```typescript
import { getUsers } from './db/queries.server'
import { createServerFn } from '@tanstack/solid-start'
// This is fine -- the server implementation is removed for the client build
export const fetchUsers = createServerFn().handler(async () => {
return getUsers()
})
// This keeps the import alive in the client build
export function leakyHelper() {
return getUsers() // referenced outside server boundary
}
```
--------------------------------
### Configure Vite for Cloudflare Workers
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Add Cloudflare plugin to vite.config.ts with TanStack Start and React plugins. The cloudflare plugin must be listed first in the plugins array.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { cloudflare } from '@cloudflare/vite-plugin'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
cloudflare({ viteEnvironment: { name: 'ssr' } }),
tanstackStart(),
viteReact(),
],
})
```
--------------------------------
### Database integration with TanStack Start server functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/databases.md
Call database adapters or clients directly within server functions to perform CRUD operations. This pattern works with any database driver or service accessible from the server.
```tsx
import { createServerFn } from '@tanstack/react-start'
const db = createMyDatabaseClient()
export const getUser = createServerFn().handler(async ({ context }) => {
const user = await db.getUser(context.userId)
return user
})
export const createUser = createServerFn({ method: 'POST' }).handler(
async ({ data }) => {
const user = await db.createUser(data)
return user
},
)
```
--------------------------------
### Add Route-Level Middleware to All Server Handlers in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Apply middleware, like `authMiddleware` and `loggerMiddleware`, to all HTTP method handlers defined within a server route using the `middleware` property.
```tsx
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
middleware: [authMiddleware, loggerMiddleware], // Applies to all handlers
handlers: {
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
},
POST: async ({ request }) => {
const body = await request.json()
return new Response(`Hello, ${body.name}!`)
}
}
}
})
```
--------------------------------
### Render Date/Time with Server-Determined Locale/Time Zone
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hydration-errors.md
This example demonstrates how to use a server function to format a date and time based on the locale and time zone determined by the server middleware, ensuring hydration consistency.
```tsx
// src/routes/index.tsx (example)
import * as React from 'react'
import { createFileRoute } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'
import { getCookie } from '@tanstack/react-start/server'
export const getServerNow = createServerFn().handler(async () => {
const locale = getCookie('locale') || 'en-US'
const timeZone = getCookie('tz') || 'UTC'
return new Intl.DateTimeFormat(locale, {
dateStyle: 'medium',
timeStyle: 'short',
timeZone,
}).format(new Date())
})
export const Route = createFileRoute('/')({
loader: () => getServerNow(),
component: () => {
const serverNow = Route.useLoaderData() as string
return
},
})
```
--------------------------------
### GET /llms.txt
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
This endpoint serves a custom 'llms.txt' file, similar to 'robots.txt', providing guidance and information to AI systems about the website's content and structure. It returns plain text content.
```APIDOC
## GET /llms.txt
### Description
This endpoint serves a custom 'llms.txt' file, similar to 'robots.txt', providing guidance and information to AI systems about the website's content and structure. It returns plain text content.
### Method
GET
### Endpoint
/llms.txt
### Parameters
#### Path Parameters
(None)
#### Query Parameters
(None)
#### Request Body
(None)
### Request Example
(Not applicable)
### Response
#### Success Response (200)
- **content** (string) - The plain text content of the llms.txt file.
#### Response Example
```
# My App
> My App is a platform for building modern web applications.
## Documentation
- Getting Started: https://myapp.com/docs/getting-started
- API Reference: https://myapp.com/docs/api
```
```
--------------------------------
### Create llms.txt Guidance File for AI Systems
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
Implements a route that serves an llms.txt file (similar to robots.txt) to provide guidance to AI systems about site content and structure. This file helps AI systems understand the site's purpose and locate key documentation resources.
```ts
// src/routes/llms[.]txt.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/llms.txt')({
server: {
handlers: {
GET: async () => {
const content = `# My App
> My App is a platform for building modern web applications.
## Documentation
- Getting Started: https://myapp.com/docs/getting-started
- API Reference: https://myapp.com/docs/api`
```
--------------------------------
### Locale and Timezone Middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hydration-errors.md
Set up server middleware to read locale from cookies or Accept-Language header and timezone from cookies, then pass both as context to the application. This ensures deterministic server rendering that matches the client.
```tsx
// src/start.ts
import { createStart, createMiddleware } from '@tanstack/solid-start'
import {
getRequestHeader,
getCookie,
setCookie,
} from '@tanstack/solid-start/server'
const localeTzMiddleware = createMiddleware().server(async ({ next }) => {
const header = getRequestHeader('accept-language')
const headerLocale = header?.split(',')[0] || 'en-US'
const cookieLocale = getCookie('locale')
const cookieTz = getCookie('tz') // set by client later (see Strategy 2)
const locale = cookieLocale || headerLocale
const timeZone = cookieTz || 'UTC'
setCookie('locale', locale, { path: '/', maxAge: 60 * 60 * 24 * 365 })
return next({ context: { locale, timeZone } })
})
export const startInstance = createStart(() => ({
requestMiddleware: [localeTzMiddleware],
}))
```
--------------------------------
### Handle POST Requests with JSON Body in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Add a POST handler to process request bodies. Use request.json() to parse the JSON body; this returns a Promise that must be awaited.
```typescript
// routes/hello.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
POST: async ({ request }) => {
const body = await request.json()
return new Response(`Hello, ${body.name}!`)
},
},
},
})
// Send a POST request to /hello with a JSON body like { "name": "Tanner" }
// Hello, Tanner!
```
--------------------------------
### Add Middleware to Specific Server Route Handlers in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Use `createHandlers` to apply middleware, such as `loggerMiddleware`, to individual HTTP method handlers within a server route.
```tsx
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: ({ createHandlers }) =>
createHandlers({
GET: {
middleware: [loggerMiddleware],
handler: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
}
}
})
}
})
```
--------------------------------
### Configure Vite for Server Components
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Update vite.config.ts to enable RSC in the TanStack Start plugin and register the Vite RSC plugin. Requires React 19+ and Vite 7+.
```tsx
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
import rsc from '@vitejs/plugin-rsc'
export default defineConfig({
plugins: [
tanstackStart({
rsc: {
enabled: true,
},
}),
rsc(),
viteReact(),
],
})
```
--------------------------------
### ImportProtectionOptions Configuration
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/import-protection.md
Complete configuration interface for import protection in TanStack Start. Defines all available options for controlling import protection behavior, including enabled state, violation behavior, logging, pattern matching, and environment-specific rules.
```APIDOC
## ImportProtectionOptions Configuration
### Description
Full configuration reference for the ImportProtectionOptions interface used to configure import protection behavior in TanStack Start projects.
### Configuration Interface
```typescript
interface ImportProtectionOptions {
enabled?: boolean
behavior?:
| 'error'
| 'mock'
| { dev?: 'error' | 'mock'; build?: 'error' | 'mock' }
log?: 'once' | 'always'
include?: Array
exclude?: Array
ignoreImporters?: Array
maxTraceDepth?: number
client?: {
specifiers?: Array
files?: Array
excludeFiles?: Array
}
server?: {
specifiers?: Array
files?: Array
excludeFiles?: Array
}
onViolation?: (
info: ViolationInfo,
) => boolean | void | Promise
}
```
### Configuration Options
#### Core Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `enabled` | `boolean` | `true` | Set to `false` to disable the plugin |
| `behavior` | `string \| object` | `{ dev: 'mock', build: 'error' }` | What to do on violation. Can be `'error'`, `'mock'`, or an object specifying different behavior for dev and build environments |
| `log` | `'once' \| 'always'` | `'once'` | Whether to deduplicate repeated violations or log all occurrences |
| `maxTraceDepth` | `number` | `20` | Maximum depth for import traces |
#### Pattern Matching Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `include` | `Pattern[]` | Start's `srcDirectory` | Only check importers matching these patterns |
| `exclude` | `Pattern[]` | `[]` | Skip importers matching these patterns |
| `ignoreImporters` | `Pattern[]` | `[]` | Ignore violations from these importers |
#### Client Environment Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `client` | `object` | See defaults below | Additional deny rules for the client environment |
| `client.specifiers` | `Pattern[]` | Framework server specifiers | Specifier patterns denied in the client environment (additive with defaults) |
| `client.files` | `Pattern[]` | `['**/*.server.*']` | File patterns denied in the client environment (replaces defaults) |
| `client.excludeFiles` | `Pattern[]` | `['**/node_modules/**']` | Resolved files matching these patterns skip resolved-target checks (replaces defaults) |
#### Server Environment Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `server` | `object` | See defaults below | Additional deny rules for the server environment |
| `server.specifiers` | `Pattern[]` | `[]` | Specifier patterns denied in the server environment (replaces defaults) |
| `server.files` | `Pattern[]` | `['**/*.client.*']` | File patterns denied in the server environment (replaces defaults) |
#### Violation Handler
| Option | Type | Description |
|--------|------|-------------|
| `onViolation` | `(info: ViolationInfo) => boolean \| void \| Promise` | Custom callback function invoked when an import violation is detected. Can return a boolean or promise to control violation handling |
### Pattern Types
Patterns can be specified as:
- **String**: Glob patterns (e.g., `'**/*.server.*'`, `'**/node_modules/**'`)
- **RegExp**: Regular expressions for more complex matching (e.g., `/\.server\./`)
### Behavior Values
- **`'error'`**: Throw an error when a violation is detected
- **`'mock'`**: Mock the import when a violation is detected
- **Object**: Specify different behavior for development and build environments:
- `dev`: Behavior during development (`'error'` or `'mock'`)
- `build`: Behavior during production build (`'error'` or `'mock'`)
```
--------------------------------
### Create New Relic Transaction Middleware (TypeScript)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Defines a TanStack Start middleware to set the New Relic controller name for server functions and routes based on the request path.
```ts
// newrelic-middleware.ts
import newrelic from 'newrelic'
import { createMiddleware } from '@tanstack/react-start'
export const nrTransactionMiddleware = createMiddleware().server(
async ({ request, next }) => {
const reqPath = new URL(request.url).pathname
newrelic.setControllerName(reqPath, request.method ?? 'GET')
return await next()
},
)
```
--------------------------------
### Configure Database Connection with Environment Variables
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-variables.md
Demonstrates creating a server function to securely retrieve database configuration from environment variables, including parsing and conditional SSL.
```typescript
// src/lib/database.ts
import { createServerFn } from '@tanstack/solid-start'
const getDatabaseConnection = createServerFn().handler(async () => {
const config = {
url: process.env.DATABASE_URL,
maxConnections: parseInt(process.env.DB_MAX_CONNECTIONS || '10'),
ssl: process.env.NODE_ENV === 'production',
}
return createConnection(config)
})
```
--------------------------------
### Configure Router in router.tsx
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/routing.md
Export a getRouter function that creates and returns a new router instance with routeTree and optional configuration like scrollRestoration. This file dictates TanStack Router behavior in Start.
```typescript
// src/router.tsx
import { createRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'
// You must export a getRouter function that
// returns a new router instance each time
export function getRouter() {
const router = createRouter({
routeTree,
scrollRestoration: true,
})
return router
}
```
--------------------------------
### TanStack Start Admin Route for Error Data
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Creates a server-side route `/admin/errors` using `createFileRoute` to expose the collected errors from the `errorStore` as a JSON response. This allows administrators to retrieve reported error data.
```tsx
// routes/errors.ts
export const Route = createFileRoute('/admin/errors')({
server: {
handlers: {
GET: async () => {
const errors = Array.from(errorStore.entries()).map(([key, data]) => ({
id: key,
...data,
}))
return Response.json({ errors })
},
},
},
})
```
--------------------------------
### Create Machine-Readable Products API Endpoint
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
Implements a server-side GET handler that returns product data in schema.org ItemList format with Product entities. This endpoint provides a machine-readable interface for AI systems and developers to consume product information with optional category filtering.
```ts
// src/routes/api/products.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/api/products')({
server: {
handlers: {
GET: async ({ request }) => {
const url = new URL(request.url)
const category = url.searchParams.get('category')
const products = await fetchProducts({ category })
return Response.json({
'@context': 'https://schema.org',
'@type': 'ItemList',
itemListElement: products.map((product, index) => ({
'@type': 'ListItem',
position: index + 1,
item: {
'@type': 'Product',
name: product.name,
description: product.description,
url: `https://myapp.com/products/${product.id}`,
},
})),
})
},
},
},
})
```
--------------------------------
### Implement Article JSON-LD Schema in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
Injects machine-readable Article metadata into a route's head section using JSON-LD. This allows AI systems to accurately identify the headline, author, and publication dates of content.
```tsx
// src/routes/posts/$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
const post = await fetchPost(params.postId)
return { post }
},
head: ({ loaderData }) => ({
meta: [{ title: loaderData.post.title }],
scripts: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
headline: loaderData.post.title,
description: loaderData.post.excerpt,
image: loaderData.post.coverImage,
author: {
'@type': 'Person',
name: loaderData.post.author.name,
url: loaderData.post.author.url,
},
publisher: {
'@type': 'Organization',
name: 'My Company',
logo: {
'@type': 'ImageObject',
url: 'https://myapp.com/logo.png',
},
},
datePublished: loaderData.post.publishedAt,
dateModified: loaderData.post.updatedAt,
}),
},
],
}),
component: PostPage,
})
```
--------------------------------
### Create Server-Side Route with API Fetch in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/fetching-external-api
This snippet defines a server-only function to securely fetch popular movies from the TMDB API and sets up a file-based route loader to call this function before rendering the page.
```typescript
// src/routes/fetch-movies.tsx
import { createFileRoute } from '@tanstack/react-router'
import type { Movie, TMDBResponse } from '../types/movie'
import { createServerFn } from '@tanstack/react-start'
const API_URL =
'https://api.themoviedb.org/3/discover/movie?include_adult=false&include_video=false&language=en-US&page=1&sort_by=popularity.desc'
const fetchPopularMovies = createServerFn().handler(
async (): Promise => {
const response = await fetch(API_URL, {
headers: {
accept: 'application/json',
Authorization: `Bearer ${process.env.TMDB_AUTH_TOKEN}`,
},
})
if (!response.ok) {
throw new Error(`Failed to fetch movies: ${response.statusText}`)
}
return response.json()
},
)
export const Route = createFileRoute('/fetch-movies')({
component: MoviesPage,
loader: async (): Promise<{ movies: Movie[]; error: string | null }> => {
try {
const moviesData = await fetchPopularMovies()
return { movies: moviesData.results, error: null }
} catch (error) {
console.error('Error fetching movies:', error)
return { movies: [], error: 'Failed to load movies' }
}
},
})
```
--------------------------------
### Render Product Details with Clear, Factual Statements in React/TSX
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
This React/TSX component example shows how to present product information in a clear, factual, and easily extractable format for AI systems. It uses standard HTML elements to structure product name, category, brand, price, and colors.
```tsx
// Good: Clear, extractable facts
function ProductDetails(props) {
return (
{props.product.name}
{props.product.name} is a {props.product.category} made by{' '}
{props.product.brand}. It costs ${props.product.price} and is available
in {props.product.colors.join(', ')}.
)
}
```
--------------------------------
### GET /api/products
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
This endpoint retrieves a list of products, optionally filtered by category. The response is structured using Schema.org's 'ItemList' and 'Product' types, making it machine-readable for AI systems and search engines.
```APIDOC
## GET /api/products
### Description
This endpoint retrieves a list of products, optionally filtered by category. The response is structured using Schema.org's 'ItemList' and 'Product' types, making it machine-readable for AI systems and search engines.
### Method
GET
### Endpoint
/api/products
### Parameters
#### Path Parameters
(None)
#### Query Parameters
- **category** (string) - Optional - Filters the product list by a specified category.
#### Request Body
(None)
### Request Example
(Not applicable for GET requests with query parameters)
### Response
#### Success Response (200)
- **@context** (string) - The Schema.org context, always "https://schema.org".
- **@type** (string) - The Schema.org type, always "ItemList".
- **itemListElement** (array) - An array of list items, each representing a product.
- **@type** (string) - The Schema.org type for a list item, always "ListItem".
- **position** (number) - The position of the item in the list.
- **item** (object) - The product details.
- **@type** (string) - The Schema.org type for a product, always "Product".
- **name** (string) - The name of the product.
- **description** (string) - A description of the product.
- **url** (string) - The canonical URL for the product page.
#### Response Example
```json
{
"@context": "https://schema.org",
"@type": "ItemList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"item": {
"@type": "Product",
"name": "Example Product A",
"description": "A detailed description of product A.",
"url": "https://myapp.com/products/1"
}
},
{
"@type": "ListItem",
"position": 2,
"item": {
"@type": "Product",
"name": "Example Product B",
"description": "A detailed description of product B.",
"url": "https://myapp.com/products/2"
}
}
]
}
```
```
--------------------------------
### Middleware Execution Order with Dependencies
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Middleware executes dependency-first: global middleware runs first, followed by server function middleware, then nested middleware in dependency order. This example demonstrates the execution sequence: globalMiddleware1, globalMiddleware2, a, b, c, d, fn.
```typescript
import { createMiddleware, createServerFn } from '@tanstack/react-start'
const globalMiddleware1 = createMiddleware({ type: 'function' }).server(
async ({ next }) => {
console.log('globalMiddleware1')
return next()
},
)
const globalMiddleware2 = createMiddleware({ type: 'function' }).server(
async ({ next }) => {
console.log('globalMiddleware2')
return next()
},
)
const a = createMiddleware({ type: 'function' }).server(async ({ next }) => {
console.log('a')
return next()
})
const b = createMiddleware({ type: 'function' })
.middleware([a])
.server(async ({ next }) => {
console.log('b')
return next()
})
const c = createMiddleware({ type: 'function' })
.middleware()
.server(async ({ next }) => {
console.log('c')
return next()
})
const d = createMiddleware({ type: 'function' })
.middleware([b, c])
.server(async () => {
console.log('d')
})
const fn = createServerFn()
.middleware([d])
.server(async () => {
console.log('fn')
})
```
--------------------------------
### Validate Client-Sent Context in Server Middleware with Zod
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
This example demonstrates how to validate client-sent context on the server using `zodValidator` to ensure data integrity and security. It parses the `workspaceId` from the context.
```tsx
import { createMiddleware } from '@tanstack/react-start'
import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
const requestLogger = createMiddleware({ type: 'function' })
.client(async ({ next, context }) => {
return next({
sendContext: {
workspaceId: context.workspaceId,
},
})
})
.server(async ({ next, data, context }) => {
// Validate the workspace ID before using it
const workspaceId = zodValidator(z.number()).parse(context.workspaceId)
console.log('Workspace ID:', workspaceId)
return next()
})
```
--------------------------------
### Manual Netlify Configuration with netlify.toml
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Manually configure Netlify build and dev settings by adding a netlify.toml file to your project root.
```toml
[build]
command = "vite build"
publish = "dist/client"
[dev]
command = "vite dev"
port = 3000
```
--------------------------------
### Create health check endpoint with system metrics
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Implement a GET endpoint that returns system health status including uptime, memory usage, database connectivity, and version info. Returns JSON response with all health check results.
```tsx
// routes/health.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/health')({
server: {
handlers: {
GET: async () => {
const checks = {
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
database: await checkDatabase(),
version: process.env.npm_package_version,
}
return Response.json(checks)
},
},
},
})
async function checkDatabase() {
try {
await db.raw('SELECT 1')
return { status: 'connected', latency: 0 }
} catch (error) {
return { status: 'error', error: error.message }
}
}
```
--------------------------------
### Create a Static robots.txt File
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
Place a static 'robots.txt' file in your 'public' directory to control search engine crawling, including a reference to your sitemap.
```txt
// public/robots.txt
User-agent: *
Allow: /
Sitemap: https://myapp.com/sitemap.xml
```
--------------------------------
### Configure Session Management in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
This utility function `useAppSession` configures and provides access to secure HTTP-only cookie sessions. It defines the session data type, a unique name, a strong password, and optional cookie settings for production environments.
```tsx
// utils/session.ts
import { useSession } from '@tanstack/react-start/server'
type SessionData = {
userId?: string
email?: string
role?: string
}
export function useAppSession() {
return useSession({
// Session configuration
name: 'app-session',
password: process.env.SESSION_SECRET!, // At least 32 characters
// Optional: customize cookie settings
cookie: {
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
httpOnly: true,
},
})
}
```
--------------------------------
### Use Tailwind CSS Classes in Components
Source: https://tanstack.com/start/latest/docs/framework/react/guide/tailwind-integration
Apply Tailwind CSS utility classes directly to JSX elements in your TanStack Start components.
```typescript
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: Home,
})
function Home() {
return
Hello World
}
```
--------------------------------
### Set Custom Headers in Response
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Configure response headers by passing a headers object in the Response constructor's options. This example sets the Content-Type header to text/plain; use this pattern for any custom header requirements.
```typescript
// routes/hello.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return new Response('Hello, World!', {
headers: {
'Content-Type': 'text/plain',
},
})
},
},
},
})
// Visit /hello to see the response
// Hello, World!
```
--------------------------------
### Analyzing Client Bundle for Server-Only Code
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
Use npm run build to generate the client bundle and inspect dist/client to ensure no server-only imports are inadvertently included.
```bash
# Analyze client bundle
npm run build
# Check dist/client for any server-only imports
```
--------------------------------
### Violation Trace: Server-only Code in Client Environment
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This diagnostic message shows an example of an import protection violation where server-only code is transitively imported into the client environment, including the trace and suggestions.
```text
[import-protection] Import denied in client environment
Denied by file pattern: **/*.server.*
Importer: src/features/auth/session.ts:5:27
Import: "../db/queries.server"
Resolved: src/db/queries.server.ts
Trace:
1. src/routes/index.tsx:2:34 (entry) (import "../features/auth/session")
2. src/features/auth/session.ts:5:27 (import "../db/queries.server")
Code:
3 | import { logger } from '../utils/logger'
4 |
> 5 | import { getUsers } from '../db/queries.server'
| ^
6 |
7 | export function loadAuth()
src/features/auth/session.ts:5:27
Suggestions:
- Wrap in createServerFn().handler(() => ...) to make it callable from the client via RPC
- Wrap in createServerOnlyFn(() => ...) if it should not be callable from the client
- Use createIsomorphicFn().client(() => ...).server(() => ...) for environment-specific implementations
- Split the file so client-safe exports are separate
```
--------------------------------
### Send Client Context to Server Middleware in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
This snippet illustrates how to explicitly send client-side context to the server using the `sendContext` property in the `next` function. The sent context becomes available in server-side middleware.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const requestLogger = createMiddleware({ type: 'function' })
.client(async ({ next, context }) => {
return next({
sendContext: {
// Send the workspace ID to the server
workspaceId: context.workspaceId,
},
})
})
.server(async ({ next, data, context }) => {
// Woah! We have the workspace ID from the client!
console.log('Workspace ID:', context.workspaceId)
return next()
})
```
--------------------------------
### Configure Nitro Plugin in Vite Config
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Add the nitro/vite plugin to your vite.config.ts file alongside TanStack Start and React plugins. The plugin integrates with Vite Environments API and is under active development.
```typescript
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { defineConfig } from 'vite'
import { nitro } from 'nitro/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [tanstackStart(), nitro(), viteReact()],
})
```
--------------------------------
### Create Health Check Endpoint with TanStack Solid Router
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
Implement a GET endpoint that returns system health status including uptime, memory usage, database connectivity, and version information.
```tsx
// routes/health.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/health')({
server: {
handlers: {
GET: async () => {
const checks = {
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
database: await checkDatabase(),
version: process.env.npm_package_version,
}
return Response.json(checks)
},
},
},
})
async function checkDatabase() {
try {
await db.raw('SELECT 1')
return { status: 'connected', latency: 0 }
} catch (error) {
return { status: 'error', error: error.message }
}
}
```
--------------------------------
### Low-Level Flight Stream APIs
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Reference for advanced Flight stream APIs available in TanStack Start for custom streaming protocols, API route integration, and external RSC-aware systems. Includes server-side rendering and client-side decoding functions.
```APIDOC
## Low-Level Flight Stream APIs
### Description
Advanced APIs for custom streaming protocols, API route integration, and external RSC-aware systems. Import from `@tanstack/react-start/rsc`.
### Available Functions
#### renderToReadableStream
- **Available in** - Server functions only
- **Description** - Renders React elements to a Flight stream
- **Parameters**
- **element** (ReactElement) - Required - React element to render
- **Returns** - ReadableStream - Flight stream of serialized React
#### createFromFetch
- **Available in** - Client
- **Description** - Decodes a Flight stream from a `Promise`
- **Parameters**
- **fetchPromise** (Promise) - Required - Fetch promise to decode
- **Returns** - Promise - Decoded React element or component
#### createFromReadableStream
- **Available in** - Client/SSR
- **Description** - Decodes a Flight stream from a `ReadableStream`
- **Parameters**
- **stream** (ReadableStream) - Required - Flight stream to decode
- **Returns** - Promise - Decoded React element or component
### Import
```tsx
import {
renderToReadableStream,
createFromFetch,
createFromReadableStream
} from '@tanstack/react-start/rsc'
```
### Client Usage Example
```tsx
import { createFromFetch } from '@tanstack/react-start/rsc'
async function fetchRSC() {
return createFromFetch(fetch('/api/rsc'))
}
```
```
--------------------------------
### Override Middleware Fetch at Call Site in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
The call site fetch override takes the highest priority over middleware. Note that custom fetch only applies on the client side and is bypassed during SSR.
```tsx
import { createMiddleware, createServerFn } from '@tanstack/react-start'
import type { CustomFetch } from '@tanstack/react-start'
// Middleware sets a fetch that adds logging
const loggingMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
const loggingFetch: CustomFetch = async (url, init) => {
console.log('Middleware fetch:', url)
return fetch(url, init)
}
return next({ fetch: loggingFetch })
},
)
const myServerFn = createServerFn()
.middleware([loggingMiddleware])
.handler(async () => {
return { message: 'Hello' }
})
// Uses middleware's loggingFetch
await myServerFn()
// Override with custom fetch for this specific call
const testFetch: CustomFetch = async (url, init) => {
console.log('Test fetch:', url)
return fetch(url, init)
}
await myServerFn({ fetch: testFetch }) // Uses testFetch, NOT loggingFetch
```
--------------------------------
### Initial Next.js Project Structure
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
The standard directory layout for a Next.js App Router project before beginning the migration.
```text
├── next.config.ts
├── package.json
├── postcss.config.mjs
├── public
│ ├── file.svg
│ ├── globe.svg
│ ├── next.svg
│ ├── vercel.svg
│ └── window.svg
├── README.md
├── src
│ └── app
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
└── tsconfig.json
```
--------------------------------
### Manage Chained Middleware Fetch Precedence in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
When multiple middlewares provide a fetch implementation, the last middleware in the chain takes precedence. This allows later middlewares to override or wrap the fetch logic of earlier ones.
```tsx
import { createMiddleware, createServerFn } from '@tanstack/react-start'
import type { CustomFetch } from '@tanstack/react-start'
const firstMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
const firstFetch: CustomFetch = (url, init) => {
const headers = new Headers(init?.headers)
headers.set('X-From', 'first-middleware')
return fetch(url, { ...init, headers })
}
return next({ fetch: firstFetch })
},
)
const secondMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
const secondFetch: CustomFetch = (url, init) => {
const headers = new Headers(init?.headers)
headers.set('X-From', 'second-middleware')
return fetch(url, { ...init, headers })
}
return next({ fetch: secondFetch })
},
)
const myServerFn = createServerFn()
.middleware([firstMiddleware, secondMiddleware])
.handler(async () => {
// Request will have X-From: 'second-middleware'
// because secondMiddleware's fetch overrides firstMiddleware's fetch
return { message: 'Hello' }
})
```
--------------------------------
### Disabling Static `NODE_ENV` Replacement in TanStack Start (TypeScript)
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-variables.md
Set `staticNodeEnv` to `false` in your `tanstackStart` plugin configuration if `NODE_ENV` needs to remain dynamic at runtime. This is useful for single builds deployed to multiple environments.
```typescript
tanstackStart({
server: {
build: {
staticNodeEnv: false, // Keep NODE_ENV dynamic at runtime
}
}
})
```
--------------------------------
### Set Custom Headers in TanStack Start Route Handler
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Pass a headers object in the second argument to the Response constructor to set custom HTTP response headers. Commonly used to set Content-Type or other metadata headers.
```typescript
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return new Response('Hello, World!', {
headers: {
'Content-Type': 'text/plain',
},
})
},
},
},
})
// Visit /hello to see the response
// Hello, World!
```
--------------------------------
### Server-Only Import Leaking into Client Build
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This example demonstrates how a server-only import (`getUsers`) can "leak" into the client build if it's referenced outside a compiler-recognized server boundary, such as in `leakyHelper()`. This will cause an import protection violation.
```ts
import { getUsers } from './db/queries.server'
import { createServerFn } from '@tanstack/react-start'
// This is fine -- the server implementation is removed for the client build
export const fetchUsers = createServerFn().handler(async () => {
return getUsers()
})
// This keeps the import alive in the client build
export function leakyHelper() {
return getUsers() // referenced outside server boundary
}
```
--------------------------------
### Create React Authentication Context for TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
This snippet sets up a React context (`AuthContext`) to share authentication state across components. It uses `useServerFn` to fetch user data via `getCurrentUserFn` and provides the user object, loading state, and a refetch function to child components.
```tsx
// contexts/auth.tsx
import { createContext, useContext, ReactNode } from 'react'
import { useServerFn } from '@tanstack/react-start'
import { getCurrentUserFn } from '../server/auth'
type User = {
id: string
email: string
role: string
}
type AuthContextType = {
user: User | null
isLoading: boolean
refetch: () => void
}
const AuthContext = createContext(undefined)
export function AuthProvider({ children }: { children: ReactNode }) {
const { data: user, isLoading, refetch } = useServerFn(getCurrentUserFn)
return (
{children}
)
}
export function useAuth() {
const context = useContext(AuthContext)
if (!context) {
throw new Error('useAuth must be used within AuthProvider')
}
return context
}
```
--------------------------------
### SSR inheritance behavior example 2
Source: https://tanstack.com/start/latest/docs/framework/react/guide/selective-ssr.md
Shows inheritance where a child route overrides a parent's 'data-only' setting with a more restrictive 'false' setting.
```tsx
root { ssr: undefined }
posts { ssr: 'data-only' }
$postId { ssr: true }
details { ssr: false }
```
--------------------------------
### Manual vs. API-Driven Environment Detection
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
Compare manual environment detection using typeof window with the API-driven approach using createIsomorphicFn for logging messages based on the execution environment.
```tsx
// Manual: You handle the logic
function logMessage(msg: string) {
if (typeof window === 'undefined') {
console.log(`[SERVER]: ${msg}`)
} else {
console.log(`[CLIENT]: ${msg}`)
}
}
// API: Framework handles it
const logMessage = createIsomorphicFn()
.server((msg) => console.log(`[SERVER]: ${msg}`))
.client((msg) => console.log(`[CLIENT]: ${msg}`))
```
--------------------------------
### Implement Product Schema for LLMO
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
Define product metadata, pricing, and availability using schema.org vocabulary to help AI assistants provide accurate product information.
```tsx
export const Route = createFileRoute('/products/$productId')({
loader: async ({ params }) => {
const product = await fetchProduct(params.productId)
return { product }
},
head: ({ loaderData }) => ({
meta: [{ title: loaderData.product.name }],
scripts: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: loaderData.product.name,
description: loaderData.product.description,
image: loaderData.product.images,
brand: {
'@type': 'Brand',
name: loaderData.product.brand,
},
offers: {
'@type': 'Offer',
price: loaderData.product.price,
priceCurrency: 'USD',
availability: loaderData.product.inStock
? 'https://schema.org/InStock'
: 'https://schema.org/OutOfStock',
},
aggregateRating: loaderData.product.rating
? {
'@type': 'AggregateRating',
ratingValue: loaderData.product.rating,
reviewCount: loaderData.product.reviewCount,
}
: undefined,
}),
},
],
}),
component: ProductPage,
})
```
--------------------------------
### Create Root Route with Metadata and Navigation in Solid
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic
Defines the root route using createRootRoute with head metadata (charset, viewport, SEO), stylesheet links, favicon configuration, and a shell component containing navigation links with active state styling. Includes error boundary and not-found component handling.
```TypeScript
///
import {
HeadContent,
Link,
Scripts,
createRootRoute,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { HydrationScript } from 'solid-js/web'
import type * as Solid from 'solid-js'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: DefaultCatchBoundary,
notFoundComponent: () => ,
shellComponent: RootDocument,
})
function RootDocument({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Set HTTP Status Code in TanStack Start Route Handler
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Pass a status property in the second argument to the Response constructor to set the HTTP status code. Useful for returning error responses like 404 when a resource is not found.
```typescript
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request, params }) => {
const user = await findUser(params.id)
if (!user) {
return new Response('User not found', {
status: 404,
})
}
return Response.json(user)
},
},
},
})
```
--------------------------------
### Send server context to client in TanStack Start
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Use the sendContext property in the server middleware's next function to transmit serialized data. The client-side next() call returns this context with full type safety for nested client middleware.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const serverTimer = createMiddleware({ type: 'function' }).server(
async ({ next }) => {
return next({
sendContext: {
// Send the current time to the client
timeFromServer: new Date(),
},
})
},
)
const requestLogger = createMiddleware({ type: 'function' })
.middleware([serverTimer])
.client(async ({ next }) => {
const result = await next()
// Woah! We have the time from the server!
console.log('Time from the server:', result.context.timeFromServer)
return result
})
```
--------------------------------
### Implement Redirects in Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Illustrates how to perform redirects from a server function using `redirect` for authentication or navigation purposes.
```tsx
import { createServerFn } from '@tanstack/react-start'
import { redirect } from '@tanstack/react-router'
export const requireAuth = createServerFn().handler(async () => {
const user = await getCurrentUser()
if (!user) {
throw redirect({ to: '/login' })
}
return user
})
```
--------------------------------
### Disable Server-Side Rendering for Specific Routes (TanStack Start)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/seo.md
Selectively disable SSR for routes that do not require SEO, such as internal dashboards, by setting the 'ssr' option to 'false'.
```tsx
export const Route = createFileRoute('/dashboard')({
ssr: false, // Dashboard doesn't need to be indexed
component: DashboardPage,
})
```
--------------------------------
### Configure Custom Gzip Compression Settings
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Adjust Gzip minimum file size threshold and specify MIME types eligible for compression to optimize compression efficiency.
```bash
ASSET_PRELOAD_GZIP_MIN_SIZE=2048 \
ASSET_PRELOAD_GZIP_MIME_TYPES="text/,application/javascript,application/json" \
bun run server.ts
```
--------------------------------
### Create Dynamic robots.txt with Server Route
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/seo.md
Generate a dynamic robots.txt at runtime using a server route for complex scenarios such as different rules per environment.
```ts
// src/routes/robots[.]txt.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/robots.txt')({
server: {
handlers: {
GET: async () => {
const robots = `User-agent: *
Allow: /
Sitemap: https://myapp.com/sitemap.xml`
return new Response(robots, {
headers: {
'Content-Type': 'text/plain',
},
})
},
},
},
})
```
--------------------------------
### Environment-Specific Client Entry Point
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/client-entry-point.md
Use Vite's import.meta.env to conditionally render components or logic specifically for development or production environments.
```tsx
// src/client.tsx
import { StartClient } from '@tanstack/solid-start/client'
import { hydrate } from 'solid-js/web'
const App = (
<>
{import.meta.env.DEV &&
Development Mode
}
>
)
hydrate(() => , document.body)
```
--------------------------------
### Create Dynamic Sitemap with Server Route
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/seo.md
Generate a dynamic sitemap at runtime using a server route for sites with dynamic content that can't be discovered at build time. Consider caching at CDN for performance.
```ts
// src/routes/sitemap[.]xml.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/sitemap.xml')({
server: {
handlers: {
GET: async () => {
const posts = await fetchAllPosts()
const sitemap = `
https://myapp.com/daily1.0
${posts
.map(
(post) => `
https://myapp.com/posts/${post.id}${post.updatedAt}weekly`,
)
.join('')}
`
return new Response(sitemap, {
headers: {
'Content-Type': 'application/xml',
},
})
},
},
},
})
```
--------------------------------
### createServerFn Client Build Output (Simplified)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This is the conceptual client build output after the compiler replaces the `createServerFn` handler with a client RPC stub. The server-only import `getUsers` is removed.
```ts
import { createClientRpc } from '@tanstack/react-start/client-rpc'
import { createServerFn } from '@tanstack/react-start'
// Compiler replaces the handler with a client RPC stub.
// (The id is generated by the compiler; treat it as an opaque identifier.)
export const fetchUsers = TanStackStart.createServerFn({
method: 'GET',
}).handler(createClientRpc('sha256:deadbeef...'))
// The server-only import is removed by the compiler.
```
--------------------------------
### Configure Static Prerendering in Vite
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/seo.md
Enable static prerendering at build time with link crawling to generate HTML for all discoverable pages, improving performance and SEO.
```ts
// vite.config.ts
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
export default defineConfig({
plugins: [
tanstackStart({
prerender: {
enabled: true,
crawlLinks: true,
},
}),
],
})
```
--------------------------------
### Create basic server middleware with .server method
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Define server-side logic that executes before nested middleware. The middleware receives `next`, `context`, and `request` parameters and must call `next()` to proceed.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().server(
({ next, context, request }) => {
return next()
},
)
```
--------------------------------
### Apply Middleware Factory to Server Functions
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Demonstrates how to use a middleware factory within a server function to enforce specific access requirements.
```tsx
import { createServerFn } from '@tanstack/solid-start'
import { authorizationMiddleware } from './middleware'
export const getClients = createServerFn()
.middleware([
authorizationMiddleware({
client: ['read'],
}),
])
.handler(async ({ context }) => {
return { message: 'The user can read clients.' }
})
```
--------------------------------
### Create Root Route with Head Metadata in Solid
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-nitro
Defines the root route using createRootRoute with head metadata including charset, viewport, SEO tags, stylesheets, favicons, and custom scripts. Includes error and not-found components, and a shell component for the document structure.
```TypeScript
///
import {
HeadContent,
Link,
Scripts,
createRootRoute,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { HydrationScript } from 'solid-js/web'
import type * as Solid from 'solid-js'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
scripts: [
{
src: '/customScript.js',
type: 'text/javascript',
},
],
}),
errorComponent: DefaultCatchBoundary,
notFoundComponent: () => ,
shellComponent: RootDocument,
})
```
--------------------------------
### Sentry Integration for Client and Server Functions
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
This snippet demonstrates how to initialize Sentry on the client-side (app.tsx) and how to capture exceptions within server functions using the `@sentry/node` package.
```tsx
// Client-side (app.tsx)
import * as Sentry from '@sentry/solid'
Sentry.init({
dsn: import.meta.env.VITE_SENTRY_DSN,
environment: import.meta.env.NODE_ENV,
})
```
```tsx
// Server functions
import * as Sentry from '@sentry/node'
const serverFn = createServerFn().handler(async () => {
try {
return await riskyOperation()
} catch (error) {
Sentry.captureException(error)
throw error
}
})
```
--------------------------------
### Implement FastResponse in Node.js Server Entry Point
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Replace the global `Response` constructor with `srvx`'s `FastResponse` in your server entry point to improve throughput in Node.js environments with Nitro.
```ts
import { FastResponse } from 'srvx'
globalThis.Response = FastResponse
```
--------------------------------
### Create Root Route with Head Metadata and Layout in Solid
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-static
Establishes the root route using createRootRoute with SEO metadata, stylesheets, favicon links, error handling, and a root layout component. The head function configures charset, viewport, and SEO tags; errorComponent and notFoundComponent handle error states.
```TypeScript
///
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { HydrationScript } from 'solid-js/web'
import type * as Solid from 'solid-js'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
```
--------------------------------
### External API Integration with TanStack SolidStart
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-variables.md
Use `createServerFn` for secure server-side API calls with secrets. For public client-side endpoints, use `useQuery` with `import.meta.env`.
```typescript
// src/lib/external-api.ts
import { createServerFn } from '@tanstack/solid-start'
// Server-side API calls (can use secret keys)
const fetchUserData = createServerFn()
.inputValidator(z.object({ userId: z.string() }))
.handler(async ({ data }) => {
const response = await fetch(
`${process.env.EXTERNAL_API_URL}/users/${data.userId}`,
{
headers: {
Authorization: `Bearer ${process.env.EXTERNAL_API_SECRET}`,
'Content-Type': 'application/json',
},
},
)
return response.json()
})
// Client-side API calls (public endpoints only)
export function usePublicData() {
const apiUrl = import.meta.env.VITE_PUBLIC_API_URL
return useQuery({
queryKey: ['public-data'],
queryFn: () => fetch(`${apiUrl}/public/stats`).then((r) => r.json()),
})
}
```
--------------------------------
### Root Layout with Navigation Links and Hydration
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-static
Provides the HTML structure, hydration scripts, and navigation menu for the application. Includes active link styling and routes to home, posts, users, pathless layout, deferred, and a non-existent route for testing.
```TypeScript/JSX
function RootLayout({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Create and call basic server function
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-functions.md
Define a server function with createServerFn() and invoke it from anywhere in the application. The handler runs only on the server and returns serializable data.
```tsx
import { createServerFn } from '@tanstack/solid-start'
export const getServerTime = createServerFn().handler(async () => {
// This runs only on the server
return new Date().toISOString()
})
// Call from anywhere - components, loaders, hooks, etc.
const time = await getServerTime()
```
--------------------------------
### Complete Isomorphic Function with createIsomorphicFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-functions.md
Demonstrates how to create an isomorphic function that provides distinct implementations for both client and server environments.
```tsx
import { createIsomorphicFn } from '@tanstack/react-start'
const getEnv = createIsomorphicFn()
.server(() => 'server')
.client(() => 'client')
const env = getEnv()
// ℹ️ On the **server**, it returns `'server'`.
// ℹ️ On the **client**, it returns `'client'`.
```
--------------------------------
### Optimize Asset Preloading for Minimal Memory Usage
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Configure asset preloading with a reduced maximum file size to minimize memory consumption on resource-constrained environments.
```bash
ASSET_PRELOAD_MAX_SIZE=1048576 bun run server.ts
```
--------------------------------
### Global Fetch Configuration via createStart
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Sets a default custom fetch for all server functions in the application via createStart. This global fetch has lower priority than middleware and call-site fetch, allowing per-function or per-call overrides.
```TypeScript
// src/start.ts
import { createStart } from '@tanstack/solid-start'
import type { CustomFetch } from '@tanstack/solid-start'
const globalFetch: CustomFetch = async (url, init) => {
console.log('Global fetch:', url)
// Add retry logic, telemetry, etc.
return fetch(url, init)
}
export const startInstance = createStart(() => {
return {
serverFns: {
fetch: globalFetch,
},
}
})
```
--------------------------------
### Create Wrangler Configuration File
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Set up wrangler.jsonc with required Cloudflare Workers configuration including compatibility date and Node.js compatibility flag.
```json
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "tanstack-start-app",
"compatibility_date": "2025-09-02",
"compatibility_flags": ["nodejs_compat"],
"main": "@tanstack/react-start/server-entry"
}
```
--------------------------------
### Create Static Server Function with Middleware
Source: https://tanstack.com/start/latest/docs/framework/react/guide/static-server-functions
Apply staticFunctionMiddleware to createServerFn to enable build-time execution and static caching. Ensure staticFunctionMiddleware is the final middleware in the chain.
```typescript
import { createServerFn } from '@tanstack/react-start'
import { staticFunctionMiddleware } from '@tanstack/start-static-server-functions'
const myServerFn = createServerFn({ method: 'GET' })
.middleware([staticFunctionMiddleware])
.handler(async () => {
return 'Hello, world!'
})
```
--------------------------------
### Augment Request Context with TypeScript Module Augmentation
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-entry-point.md
This example shows how to augment the Register interface to add a custom requestContext type, allowing typed data to be passed into server-side request handlers.
```tsx
import handler, { createServerEntry } from '@tanstack/solid-start/server-entry'
type MyRequestContext = {
hello: string
foo: number
}
declare module '@tanstack/solid-start' {
interface Register {
server: {
requestContext: MyRequestContext
}
}
}
export default createServerEntry({
async fetch(request) {
return handler.fetch(request, { context: { hello: 'world', foo: 123 } })
}
})
```
--------------------------------
### Add sample jokes to jokes.json
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/reading-writing-file
Populates the `jokes.json` file with an array of sample joke objects, each containing an ID, question, and answer.
```json
[
{
"id": "1",
"question": "Why don't keyboards sleep?",
"answer": "Because they have two shifts"
},
{
"id": "2",
"question": "Are you a RESTful API?",
"answer": "Because you GET my attention, PUT some love, POST the cutest smile, and DELETE my bad day"
},
{
"id": "3",
"question": "I used to know a joke about Java",
"answer": "But I ran out of memory."
},
{
"id": "4",
"question": "Why do Front-End Developers eat lunch alone?",
"answer": "Because, they don't know how to join tables."
},
{
"id": "5",
"question": "I am declaring a war.",
"answer": "var war;"
}
]
```
--------------------------------
### createServerOnlyFn Client Build Output
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This is the conceptual client build output for `createServerOnlyFn`. The function is replaced with an error-throwing stub, and the server-only import `getUsers` is removed.
```ts
export const leakyHelper = () => {
throw new Error(
'createServerOnlyFn() functions can only be called on the server!',
)
}
```
--------------------------------
### Create TanStack SolidStart Route with Server Function for TMDB API
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/fetching-external-api.md
This snippet defines a SolidStart route (`/fetch-movies`) that uses `createServerFn` to securely fetch popular movies from the TMDB API on the server, preventing client-side exposure of API credentials. The route's loader then calls this server function to provide data to the component.
```typescript
// src/routes/fetch-movies.tsx
import { createFileRoute } from '@tanstack/solid-router'
import type { Movie, TMDBResponse } from '../types/movie'
import { createServerFn } from '@tanstack/solid-start'
const API_URL =
'https://api.themoviedb.org/3/discover/movie?include_adult=false&include_video=false&language=en-US&page=1&sort_by=popularity.desc'
const fetchPopularMovies = createServerFn().handler(
async (): Promise => {
const response = await fetch(API_URL, {
headers: {
accept: 'application/json',
Authorization: `Bearer ${process.env.TMDB_AUTH_TOKEN}`,
},
})
if (!response.ok) {
throw new Error(`Failed to fetch movies: ${response.statusText}`)
}
return response.json()
},
)
export const Route = createFileRoute('/fetch-movies')({
component: MoviesPage,
loader: async (): Promise<{ movies: Movie[]; error: string | null }> => {
try {
const moviesData = await fetchPopularMovies()
return { movies: moviesData.results, error: null }
} catch (error) {
console.error('Error fetching movies:', error)
return { movies: [], error: 'Failed to load movies' }
}
},
})
```
--------------------------------
### Create Environment File for TMDB API Token
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/fetching-external-api
Create a .env file in the project root to store the TMDB API authentication token. Ensure .env is added to .gitignore to keep API keys secure.
```bash
touch .env
```
```dotenv
TMDB_AUTH_TOKEN=your_bearer_token_here
```
--------------------------------
### Configure Prerendering Options in vite.config.ts
Source: https://tanstack.com/start/latest/docs/framework/react/guide/static-prerendering
This snippet shows the `tanstackStart` plugin configuration in `vite.config.ts` to enable and customize prerendering. It includes settings for automatic static path discovery, concurrency, link crawling, and page-specific prerendering rules.
```typescript
// vite.config.ts
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
tanstackStart({
prerender: {
// Switch to true to enable prerendering
enabled: false,
// Disable if you need pages to be at `/page.html` instead of `/page/index.html`
autoSubfolderIndex: true,
// If disabled, only the root path or the paths defined in the pages config will be prerendered
autoStaticPathsDiscovery: true,
// How many prerender jobs to run at once
concurrency: 14,
// Whether to extract links from the HTML and prerender them also
crawlLinks: true,
// Filter function takes the page object and returns whether it should prerender
filter: ({ path }) => !path.startsWith('/do-not-render-me'),
// Number of times to retry a failed prerender job
retryCount: 2,
// Delay between retries in milliseconds
retryDelay: 1000,
// Maximum number of redirects to follow during prerendering
maxRedirects: 5,
// Fail if an error occurs during prerendering
failOnError: true,
// Callback when page is successfully rendered
onSuccess: ({ page }) => {
console.log(`Rendered ${page.path}!`)
},
},
// Optional configuration for specific pages
// Note: When autoStaticPathsDiscovery is enabled (default), discovered static
// routes will be merged with the pages specified below
pages: [
{
path: '/my-page',
prerender: { enabled: true, outputPath: '/my-page/index.html' },
},
],
}),
viteReact(),
],
})
```
--------------------------------
### Enable full SSR with ssr: true
Source: https://tanstack.com/start/latest/docs/framework/react/guide/selective-ssr.md
Default behavior that executes `beforeLoad` and `loader` on the server, renders the component on the server, and sends HTML to the client. Both hooks run on the client for subsequent navigation.
```typescript
// src/routes/posts/$postId.tsx
export const Route = createFileRoute('/posts/$postId')({
ssr: true,
beforeLoad: () => {
console.log('Executes on the server during the initial request')
console.log('Executes on the client for subsequent navigation')
},
loader: () => {
console.log('Executes on the server during the initial request')
console.log('Executes on the client for subsequent navigation')
},
component: () =>
This component is rendered on the server
,
})
```
--------------------------------
### Option A: Split File for Server Functions (src/users.server.ts)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This snippet shows how to split a file to isolate server-only functions. `fetchUsers` is safe to import from client code because the compiler rewrites its handler.
```ts
// src/users.server.ts
import { getUsers } from './db/queries.server'
import { createServerFn } from '@tanstack/react-start'
// Safe to import from client code (compiler rewrites the handler)
export const fetchUsers = createServerFn().handler(async () => {
return getUsers()
})
```
--------------------------------
### Configure Automatic Sitemap Generation
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/seo.md
Enable automatic sitemap generation at build time by crawling all discoverable pages from routes. Recommended for static or mostly-static sites.
```ts
// vite.config.ts
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
export default defineConfig({
plugins: [
tanstackStart({
prerender: {
enabled: true,
crawlLinks: true, // Discovers all linkable pages
},
sitemap: {
enabled: true,
host: 'https://myapp.com',
},
}),
],
})
```
--------------------------------
### Client-side External API Integration with useQuery
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Shows how to fetch public data from an external API on the client-side using `useQuery` and `import.meta.env`.
```typescript
// Client-side API calls (public endpoints only)
export function usePublicData() {
const apiUrl = import.meta.env.VITE_PUBLIC_API_URL
return useQuery({
queryKey: ['public-data'],
queryFn: () => fetch(`${apiUrl}/public/stats`).then((r) => r.json()),
})
}
```
--------------------------------
### File Structure for Dynamic Route
Source: https://tanstack.com/start/latest/docs/framework/react/guide/routing.md
Illustrates the directory structure for defining a dynamic route in TanStack Router.
```text
src/
├── routes
│ ├── posts/$postId.tsx
```
--------------------------------
### Create router configuration file
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Set up src/router.tsx to configure TanStack Router with the generated route tree. This file controls preloading and caching behavior. The routeTree.gen.ts file is auto-generated on first run.
```typescript
// src/router.tsx
import { createRouter } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function getRouter() {
const router = createRouter({
routeTree,
scrollRestoration: true,
})
return router
}
```
--------------------------------
### Configure Sentry for Client and Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Initialize Sentry on the client and capture exceptions within server functions. Requires @sentry/react for the client and @sentry/node for server-side logic.
```tsx
// Client-side (app.tsx)
import * as Sentry from '@sentry/react'
Sentry.init({
dsn: import.meta.env.VITE_SENTRY_DSN,
environment: import.meta.env.NODE_ENV,
})
// Server functions
import * as Sentry from '@sentry/node'
const serverFn = createServerFn().handler(async () => {
try {
return await riskyOperation()
} catch (error) {
Sentry.captureException(error)
throw error
}
})
```
--------------------------------
### Manage Loading States in Forms with createSignal
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/authentication.md
Illustrates how to manage loading states in a form using SolidJS's `createSignal` and a server function mutation. This provides user feedback during asynchronous operations.
```tsx
function LoginForm() {
const [isLoading, setIsLoading] = createSignal(false)
const loginMutation = useServerFn(loginFn)
const handleSubmit = async (data: LoginData) => {
setIsLoading(true)
try {
await loginMutation.mutate(data)
} catch (error) {
// Handle error
} finally {
setIsLoading(false)
}
}
return (
)
}
```
--------------------------------
### Basic SPA Shell Redirect with Netlify
Source: https://tanstack.com/start/latest/docs/framework/react/guide/spa-mode
Configure Netlify's _redirects file to catch all 404 requests and rewrite them to the SPA shell at /_shell.html.
```plaintext
# Catch all other 404 requests and rewrite them to the SPA shell
/* /_shell.html 200
```
--------------------------------
### Email/Password Registration and Authentication with Bcrypt
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/authentication.md
Implement user registration with password hashing and authentication verification using bcrypt. Includes session creation and user lookup utilities.
```tsx
// server/auth.ts
import bcrypt from 'bcryptjs'
import { createServerFn } from '@tanstack/solid-start'
// User registration
export const registerFn = createServerFn({ method: 'POST' })
.inputValidator(
(data: { email: string; password: string; name: string }) => data,
)
.handler(async ({ data }) => {
// Check if user exists
const existingUser = await getUserByEmail(data.email)
if (existingUser) {
return { error: 'User already exists' }
}
// Hash password
const hashedPassword = await bcrypt.hash(data.password, 12)
// Create user
const user = await createUser({
email: data.email,
password: hashedPassword,
name: data.name,
})
// Create session
const session = await useAppSession()
await session.update({ userId: user.id })
return { success: true, user: { id: user.id, email: user.email } }
})
async function authenticateUser(email: string, password: string) {
const user = await getUserByEmail(email)
if (!user) return null
const isValid = await bcrypt.compare(password, user.password)
return isValid ? user : null
}
```
--------------------------------
### Create router configuration
Source: https://tanstack.com/start/latest/docs/framework/solid/build-from-scratch.md
Set up the router configuration file that dictates TanStack Router behavior, including preloading and caching settings. This file references the auto-generated routeTree.gen.ts.
```typescript
// src/router.tsx
import { createRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'
export function getRouter() {
const router = createRouter({
routeTree,
scrollRestoration: true,
})
return router
}
```
--------------------------------
### Default Server Entry Implementation
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-entry-point
Standard implementation in src/server.ts using createServerEntry and the default handler.
```tsx
// src/server.ts
import handler, { createServerEntry } from '@tanstack/react-start/server-entry'
export default createServerEntry({
fetch(request) {
return handler.fetch(request)
},
})
```
--------------------------------
### GET /api/rsc - Flight Stream API Route
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
API endpoint that renders React elements to a Flight stream for advanced use cases. Returns a readable stream with React Flight protocol content that can be decoded on the client.
```APIDOC
## GET /api/rsc
### Description
API route that renders React elements to a Flight stream. Used for custom streaming protocols and advanced RSC integrations.
### Method
GET
### Endpoint
/api/rsc
### Response
#### Success Response (200)
- **Content-Type** (string) - `text/x-component` - Flight stream content type
- **Body** (ReadableStream) - React Flight stream containing serialized React elements
### Response Headers
```
Content-Type: text/x-component
```
### Implementation Example
```tsx
import { createAPIFileRoute } from '@tanstack/react-start/api'
import { createServerFn } from '@tanstack/react-start'
import { renderToReadableStream } from '@tanstack/react-start/rsc'
const getFlightStream = createServerFn({ method: 'GET' }).handler(async () => {
return renderToReadableStream(
Server Rendered Content
)
})
export const APIRoute = createAPIFileRoute('/api/rsc')({
GET: async () => {
const stream = await getFlightStream()
return new Response(stream, {
headers: { 'Content-Type': 'text/x-component' },
})
},
})
```
```
--------------------------------
### Create and Compose Middleware
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Create middleware using `createMiddleware()` and compose multiple middleware by passing them to the `.middleware()` method. Dependent middleware can chain operations hierarchically.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
const authMiddleware = createMiddleware()
.middleware([loggingMiddleware])
.server(() => {
//...
})
```
--------------------------------
### Create Server Function to Fetch Remote Markdown
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Define a server function using `@tanstack/react-start` to fetch markdown content from a GitHub repository, parse its front matter, and return the structured data.
```tsx
// src/utils/docs.server.ts
import { createServerFn } from '@tanstack/react-start'
import matter from 'gray-matter'
type FetchDocsParams = {
repo: string // e.g., 'tanstack/router'
branch: string // e.g., 'main'
filePath: string // e.g., 'docs/guide/getting-started.md'
}
export const fetchDocs = createServerFn({ method: 'GET' })
.inputValidator((params: FetchDocsParams) => params)
.handler(async ({ data: { repo, branch, filePath } }) => {
const url = `https://raw.githubusercontent.com/${repo}/${branch}/${filePath}`
const response = await fetch(url, {
headers: {
// Add GitHub token for private repos or higher rate limits
// Authorization: `token ${process.env.GITHUB_TOKEN}`,
},
})
if (!response.ok) {
throw new Error(`Failed to fetch: ${response.status}`)
}
const rawContent = await response.text()
const { data: frontmatter, content } = matter(rawContent)
return {
frontmatter,
content,
filePath,
}
})
```
--------------------------------
### Email and Password Authentication with Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
Implements user registration using server functions with bcrypt for password hashing. The session is updated immediately after user creation to log the user in.
```tsx
// server/auth.ts
import bcrypt from 'bcryptjs'
import { createServerFn } from '@tanstack/react-start'
// User registration
export const registerFn = createServerFn({ method: 'POST' })
.inputValidator(
(data: { email: string; password: string; name: string }) => data,
)
.handler(async ({ data }) => {
// Check if user exists
const existingUser = await getUserByEmail(data.email)
if (existingUser) {
return { error: 'User already exists' }
}
// Hash password
const hashedPassword = await bcrypt.hash(data.password, 12)
// Create user
const user = await createUser({
email: data.email,
password: hashedPassword,
name: data.name,
})
// Create session
const session = await useAppSession()
await session.update({ userId: user.id })
return { success: true, user: { id: user.id, email: user.email } }
})
async function authenticateUser(email: string, password: string) {
const user = await getUserByEmail(email)
if (!user) return null
const isValid = await bcrypt.compare(password, user.password)
return isValid ? user : null
}
```
--------------------------------
### CSS in Server Components
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Explains how CSS Modules and global CSS imports work within server components. Styles are automatically extracted and sent to the client for proper styling of server-rendered content.
```APIDOC
## CSS in Server Components
### Description
CSS Modules and global CSS imports are supported in server components. Styles are extracted and sent to the client automatically.
### Supported CSS Features
- CSS Modules (`.module.css` files)
- Global CSS imports
- Style extraction and client delivery
### Usage Example
```tsx
import styles from './Card.module.css'
const getCard = createServerFn().handler(async () => {
return renderServerComponent(
Server Rendered
,
)
})
```
```
--------------------------------
### Configure Prerendering in vite.config.ts
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/static-prerendering.md
Enable and configure static prerendering with options for automatic route discovery, link crawling, concurrency, retry logic, and success callbacks. Place this configuration in the tanstackStart plugin within vite.config.ts.
```typescript
// vite.config.ts
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
import viteSolid from 'vite-plugin-solid'
export default defineConfig({
plugins: [
tanstackStart({
prerender: {
// Enable prerendering
enabled: true,
// Enable if you need pages to be at `/page/index.html` instead of `/page.html`
autoSubfolderIndex: true,
// If disabled, only the root path or the paths defined in the pages config will be prerendered
autoStaticPathsDiscovery: true,
// How many prerender jobs to run at once
concurrency: 14,
// Whether to extract links from the HTML and prerender them also
crawlLinks: true,
// Filter function takes the page object and returns whether it should prerender
filter: ({ path }) => !path.startsWith('/do-not-render-me'),
// Number of times to retry a failed prerender job
retryCount: 2,
// Delay between retries in milliseconds
retryDelay: 1000,
// Maximum number of redirects to follow during prerendering
maxRedirects: 5,
// Fail if an error occurs during prerendering
failOnError: true,
// Callback when page is successfully rendered
onSuccess: ({ page }) => {
console.log(`Rendered ${page.path}!`)
},
},
// Optional configuration for specific pages
// Note: When autoStaticPathsDiscovery is enabled (default), discovered static
// routes will be merged with the pages specified below
pages: [
{
path: '/my-page',
prerender: { enabled: true, outputPath: '/my-page/index.html' },
},
],
}),
viteSolid({ ssr: true }),
],
})
```
--------------------------------
### Root Route Configuration with Head Metadata and Error Handlers
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-static
Configures the root route with favicon/manifest links in head metadata, error boundary component, not-found handler, and main component. Use this to set up the application's root route with proper error handling and SEO metadata.
```TypeScript/JSX
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
```
--------------------------------
### Custom Server Handler Implementation
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-entry-point
Use defineHandlerCallback and createStartHandler to inject custom logic into the rendering process.
```tsx
// src/server.ts
import {
createStartHandler,
defaultStreamHandler,
defineHandlerCallback,
} from '@tanstack/react-start/server'
import { createServerEntry } from '@tanstack/react-start/server-entry'
const customHandler = defineHandlerCallback((ctx) => {
// add custom logic here
return defaultStreamHandler(ctx)
})
const fetch = createStartHandler(customHandler)
export default createServerEntry({
fetch,
})
```
--------------------------------
### Implement Article Schema for LLMO
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/llmo.md
Use the head property in createFileRoute to inject JSON-LD structured data for articles, helping AI systems understand authorship and publication details.
```tsx
// src/routes/posts/$postId.tsx
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
const post = await fetchPost(params.postId)
return { post }
},
head: ({ loaderData }) => ({
meta: [{ title: loaderData.post.title }],
scripts: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
headline: loaderData.post.title,
description: loaderData.post.excerpt,
image: loaderData.post.coverImage,
author: {
'@type': 'Person',
name: loaderData.post.author.name,
url: loaderData.post.author.url,
},
publisher: {
'@type': 'Organization',
name: 'My Company',
logo: {
'@type': 'ImageObject',
url: 'https://myapp.com/logo.png',
},
},
datePublished: loaderData.post.publishedAt,
dateModified: loaderData.post.updatedAt,
}),
},
],
}),
component: PostPage,
})
```
--------------------------------
### Implement FAQ Schema for AI Extraction
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
Creates a FAQ route with JSON-LD FAQPage schema that structures Q&A pairs for AI systems and search engines. The schema maps FAQ data from a loader into structured Question and Answer entities, making content easily extractable by LLMO systems.
```tsx
export const Route = createFileRoute('/faq')({
loader: async () => {
const faqs = await fetchFAQs()
return { faqs }
},
head: ({ loaderData }) => ({
meta: [{ title: 'Frequently Asked Questions' }],
scripts: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: loaderData.faqs.map((faq) => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer,
},
})),
}),
},
],
}),
component: FAQPage,
})
```
--------------------------------
### Root Document Layout with Navigation and User Context
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-auth
Renders the HTML document structure with head content, navigation links, and conditional user authentication UI. Uses route context to access user data from the server loader.
```TypeScript
function RootDocument({ children }: { children: Solid.JSX.Element }) {
const routeContext = Route.useRouteContext()
return (
{children}
)
}
```
--------------------------------
### Root Component and Layout with Navigation in Solid
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-static
Defines the RootComponent that renders the layout with Outlet for child routes, and RootLayout that wraps the HTML structure with HydrationScript, HeadContent, navigation links, and development tools. Navigation links use activeProps and activeOptions for styling active routes.
```TypeScript
function RootComponent() {
return (
)
}
function RootLayout({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Preload Only Critical Assets with Include and Exclude Patterns
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Selectively preload JavaScript and CSS files while excluding source maps and vendor bundles to optimize memory usage and startup time.
```bash
ASSET_PRELOAD_INCLUDE_PATTERNS="*.js,*.css" \
ASSET_PRELOAD_EXCLUDE_PATTERNS="*.map,vendor-*" \
bun run server.ts
```
--------------------------------
### Define client-side middleware logic with .client method
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Use `.client` to wrap RPC execution and results. Call `next()` to execute the next middleware in the chain and eventually the server function call.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next, context, request }) => {
const result = await next() // <-- This will execute the next middleware in the chain and eventually, the RPC to the server
return result
},
)
```
--------------------------------
### Header Merging Across Multiple Middlewares
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Demonstrates how multiple middlewares merge headers, with later middlewares overriding earlier ones. Shows the final merged result with precedence rules applied.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const firstMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
return next({
headers: {
'X-Request-ID': '12345',
'X-Source': 'first-middleware',
},
})
},
)
const secondMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
return next({
headers: {
'X-Timestamp': Date.now().toString(),
'X-Source': 'second-middleware', // Overrides first middleware
},
})
},
)
// Final headers will include:
// - X-Request-ID: '12345' (from first)
// - X-Timestamp: '' (from second)
// - X-Source: 'second-middleware' (second overrides first)
```
--------------------------------
### Configure Root Route and Global Layout
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-static
Defines the root route using createRootRoute, incorporating SEO metadata, global stylesheets, and the main application layout with navigation.
```tsx
///
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
import * as React from 'react'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootLayout({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Root Document Layout with Navigation
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-solid-query
HTML document structure with head content, hydration script, and navigation links with active state styling. Uses TanStack Router's Link component with activeProps and activeOptions.
```TypeScript
function RootDocument({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Convert Next.js Server Actions to TanStack Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Replace 'use server' directive with createServerFn from @tanstack/react-start. Wrap the handler function and update the export syntax.
```tsx
- 'use server' // [!code --]
+ import { createServerFn } from "@tanstack/react-start" // [!code ++]
- export const create = async () => { // [!code --]
+ export const create = createServerFn().handler(async () => { // [!code ++]
return true
- } // [!code --]
+ }) // [!code ++]
```
--------------------------------
### Fetch Multiple Independent Server Components in Parallel
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Use `Promise.all` within a loader to concurrently fetch and render multiple independent server components from different data sources.
```tsx
const getArticleA = createServerFn().handler(async () => {
const article = await db.articles.findById('a')
return renderServerComponent()
})
const getArticleB = createServerFn().handler(async () => {
const article = await db.articles.findById('b')
return renderServerComponent()
})
const getSidebar = createServerFn().handler(async () => {
const trending = await db.articles.getTrending()
return renderServerComponent()
})
export const Route = createFileRoute('/news')({
loader: async () => {
const [ArticleA, ArticleB, Sidebar] = await Promise.all([
getArticleA(),
getArticleB(),
getSidebar(),
])
return { ArticleA, ArticleB, Sidebar }
},
component: NewsPage,
})
function NewsPage() {
const { ArticleA, ArticleB, Sidebar } = Route.useLoaderData()
return (
{ArticleA}
{ArticleB}
)
}
```
--------------------------------
### Integrate Dynamic Data into SPA Shell with Loaders
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/spa-mode.md
Utilize a `loader` on the Root Route to fetch and include dynamic data directly into the prerendered SPA shell.
```tsx
// src/routes/__root.tsx
export const RootRoute = createRootRoute({
loader: async () => {
return {
name: 'Tanner'
}
},
component: Root
})
export default function Root() {
const { name } = useLoaderData()
return (
Hello, {name}!
)
}
```
--------------------------------
### Root Component with Navigation and Devtools
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-react-query
Renders the root layout with navigation links to Home, Posts, Users, Pathless Layout, and Deferred routes. Includes TanStack Router and React Query devtools for development. The navigation uses activeProps to highlight the current route.
```TypeScript
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Wire Form to Server Action with Solid.js
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/reading-writing-file.md
Connect a Solid form component to the addJoke server function with state management, error handling, and data refresh. Requires importing the server action and useRouter hook.
```tsx
//JokeForm.tsx
import { createSignal } from 'solid'
import { useRouter } from '@tanstack/solid-router'
import { addJoke } from '../serverActions/jokesActions'
export function JokeForm() {
const router = useRouter()
const [question, setQuestion] = createSignal('')
const [answer, setAnswer] = createSignal('')
const [isSubmitting, setIsSubmitting] = createSignal(false)
const [error, setError] = createSignal(null)
const handleSubmit = async () => {
if (!question() || !answer() || isSubmitting()) return
try {
setIsSubmitting(true)
await addJoke({
data: { question(), answer() },
})
// Clear form
setQuestion('')
setAnswer('')
// Refresh data
router.invalidate()
} catch (error) {
console.error('Failed to add joke:', error)
setError('Failed to add joke')
} finally {
setIsSubmitting(false)
}
}
return (
)
}
```
--------------------------------
### Configure Netlify Vite plugin
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Add the Netlify adapter to your Vite configuration to enable Netlify-specific build features.
```ts
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
import netlify from '@netlify/vite-plugin-tanstack-start' // ← add this
import viteSolid from 'vite-plugin-solid'
export default defineConfig({
plugins: [
tanstackStart(),
netlify(), // ← add this (anywhere in the array is fine)
viteSolid({ ssr: true }),
],
})
```
--------------------------------
### Collect and expose performance metrics with statistics
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Implement a MetricsCollector class to record timing data and calculate percentiles (p50, p95), averages, and min/max values. Expose metrics via a /metrics endpoint that returns system and application statistics.
```tsx
// utils/metrics.ts
class MetricsCollector {
private metrics = new Map()
recordTiming(name: string, duration: number) {
if (!this.metrics.has(name)) {
this.metrics.set(name, [])
}
this.metrics.get(name)!.push(duration)
}
getStats(name: string) {
const timings = this.metrics.get(name) || []
if (timings.length === 0) return null
const sorted = timings.sort((a, b) => a - b)
return {
count: timings.length,
avg: timings.reduce((a, b) => a + b, 0) / timings.length,
p50: sorted[Math.floor(sorted.length * 0.5)],
p95: sorted[Math.floor(sorted.length * 0.95)],
min: sorted[0],
max: sorted[sorted.length - 1],
}
}
getAllStats() {
const stats: Record = {}
for (const [name] of this.metrics) {
stats[name] = this.getStats(name)
}
return stats
}
}
export const metrics = new MetricsCollector()
// Metrics endpoint
// routes/metrics.ts
export const Route = createFileRoute('/metrics')({
server: {
handlers: {
GET: async () => {
return Response.json({
system: {
uptime: process.uptime(),
memory: process.memoryUsage(),
timestamp: new Date().toISOString(),
},
application: metrics.getAllStats(),
})
},
},
},
})
```
--------------------------------
### Manage loading state during login
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
Track loading state while executing the login mutation to disable the button and show feedback to the user during the request.
```tsx
function LoginForm() {
const [isLoading, setIsLoading] = useState(false)
const loginMutation = useServerFn(loginFn)
const handleSubmit = async (data: LoginData) => {
setIsLoading(true)
try {
await loginMutation.mutate(data)
} catch (error) {
// Handle error
} finally {
setIsLoading(false)
}
}
return (
)
}
```
--------------------------------
### SolidStart Components for Displaying Movie Data
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/fetching-external-api.md
These SolidJS components (`MovieCard` and `MovieDetails`) are designed to render individual movie entries and their detailed information. They consume movie data, typically fetched by a route loader, to display titles, overviews, release dates, and ratings.
```tsx
// MovieCard component
const MovieCard = ({ movie }: { movie: Movie }) => {
return (
{movie.poster_path && (
)}
)
}
// MovieDetails component
const MovieDetails = ({ movie }: { movie: Movie }) => {
return (
<>
>
)
}
```
--------------------------------
### Root Route Creation with QueryClient Context
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-trellaux
Creates a root route with QueryClient context using createRootRouteWithContext. This establishes the context type for all child routes and enables type-safe access to the query client throughout the application.
```TypeScript
export const Route = createRootRouteWithContext<{
queryClient: QueryClient
}>()({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
```
--------------------------------
### Implement Dynamic Markdown Routes in TanStack React Router
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Utilize createFileRoute with a loader to fetch markdown data dynamically based on URL path parameters.
```tsx
// src/routes/docs.$path.tsx
import { createFileRoute } from '@tanstack/react-router'
import { fetchDocs } from '~/utils/docs.server'
import { Markdown } from '~/components/Markdown'
export const Route = createFileRoute('/docs/$path')({
loader: async ({ params }) => {
return fetchDocs({
data: {
repo: 'your-org/your-repo',
branch: 'main',
filePath: `docs/${params.path}.md`,
},
})
},
component: DocsPage,
})
function DocsPage() {
const { frontmatter, content } = Route.useLoaderData()
return (
{frontmatter.title}
)
}
```
--------------------------------
### Configure Global Server Function Middleware in src/start.ts
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Add middleware to the functionMiddleware array in src/start.ts to run for every server function in the application.
```typescript
// src/start.ts
import { createStart } from '@tanstack/react-start'
import { loggingMiddleware } from './middleware'
export const startInstance = createStart(() => {
return {
functionMiddleware: [loggingMiddleware],
}
})
```
--------------------------------
### Responding with JSON from Server Routes
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Return JSON data by manually setting headers or using the Response.json helper for automatic serialization and content-type configuration.
```ts
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return new Response(JSON.stringify({ message: 'Hello, World!' }), {
headers: {
'Content-Type': 'application/json',
},
})
},
},
},
})
// Visit /hello to see the response
// {"message":"Hello, World!"}
```
```ts
// routes/hello.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/hello')({
server: {
handlers: {
GET: async ({ request }) => {
return Response.json({ message: 'Hello, World!' })
},
},
},
})
// Visit /hello to see the response
// {"message":"Hello, World!"}
```
--------------------------------
### Root Document Layout with Navigation and Devtools
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-trellaux
HTML document structure with header navigation, main content area, and development tools (ReactQueryDevtools, TanStackRouterDevtools). Uses Tailwind CSS for styling and includes the Toaster component for notifications.
```TypeScript
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Trellaux
a TanStack Demo
{/*
*/}
{children}
)
}
```
--------------------------------
### Client-Only Execution with createClientOnlyFn and ClientOnly
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
Use createClientOnlyFn for browser utilities that throw errors if called on server, and ClientOnly component to render content only after hydration with a fallback.
```tsx
import { createClientOnlyFn } from '@tanstack/react-start'
import { ClientOnly } from '@tanstack/react-router'
// Utility: Client-only, server crashes if called
const saveToStorage = createClientOnlyFn((key: string, value: any) => {
localStorage.setItem(key, JSON.stringify(value))
})
// Component: Only renders children after hydration
function Analytics() {
return (
)
}
```
--------------------------------
### Create Environment-Aware Storage with Isomorphic Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/code-execution-patterns.md
Define separate implementations for server and client environments within a single utility to handle environment-specific APIs.
```tsx
const storage = createIsomorphicFn()
.server((key: string) => {
// Server: File-based cache
const fs = require('node:fs')
return JSON.parse(fs.readFileSync('.cache', 'utf-8'))[key]
})
.client((key: string) => {
// Client: localStorage
return JSON.parse(localStorage.getItem(key) || 'null')
})
```
--------------------------------
### Override Fetch at Call Site with Middleware
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Demonstrates how to set a logging fetch in middleware and override it with a custom fetch at the call site. The call-site fetch takes precedence over middleware fetch.
```TypeScript
import { createMiddleware, createServerFn } from '@tanstack/solid-start'
import type { CustomFetch } from '@tanstack/solid-start'
// Middleware sets a fetch that adds logging
const loggingMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
const loggingFetch: CustomFetch = async (url, init) => {
console.log('Middleware fetch:', url)
return fetch(url, init)
}
return next({ fetch: loggingFetch })
},
)
const myServerFn = createServerFn()
.middleware([loggingMiddleware])
.handler(async () => {
return { message: 'Hello' }
})
// Uses middleware's loggingFetch
await myServerFn()
// Override with custom fetch for this specific call
const testFetch: CustomFetch = async (url, init) => {
console.log('Test fetch:', url)
return fetch(url, init)
}
await myServerFn({ fetch: testFetch }) // Uses testFetch, NOT loggingFetch
```
--------------------------------
### Client Build Output with RPC Stub
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/import-protection.md
Simplified compiler output for the client build showing the handler replaced with a client RPC stub and the server-only import removed.
```typescript
import { createClientRpc } from '@tanstack/solid-start/client-rpc'
import { createServerFn } from '@tanstack/solid-start'
// Compiler replaces the handler with a client RPC stub.
// (The id is generated by the compiler; treat it as an opaque identifier.)
export const fetchUsers = TanStackStart.createServerFn({
method: 'GET',
}).handler(createClientRpc('sha256:deadbeef...'))
// The server-only import is removed by the compiler.
```
--------------------------------
### Update package.json Scripts
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Configure the project to use Vite for development and build, and Node.js for the production server.
```json
{
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"start": "node .output/server/index.mjs"
}
}
```
--------------------------------
### Root Layout Component with Navigation and Authentication
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-auth
Implement the main root component that renders the document structure with navigation links, conditional authentication UI, and route outlet. Uses Route.useRouteContext() to access user data from route context.
```TypeScript
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
const { user } = Route.useRouteContext()
return (
Home
{' '}
Posts
{user ? (
<>
{user.email}
Logout
>
) : (
Login
)}
{children}
)
}
```
--------------------------------
### Root Component with AuthKit and Layout
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-workos
Main root component that wraps the application with AuthKitProvider, Theme, and layout structure. Accesses loader data via Route.useLoaderData() and renders navigation, main content outlet, and footer.
```TypeScript
function RootComponent() {
const { auth, url } = Route.useLoaderData();
return (
Loading...
}>
);
}
```
--------------------------------
### Configure default SSR behavior
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/selective-ssr.md
Set the default SSR behavior for all routes using the defaultSsr option in createStart.
```tsx
// src/start.ts
import { createStart } from '@tanstack/solid-start'
export const startInstance = createStart(() => ({
// Disable SSR by default
defaultSsr: false,
}))
```
--------------------------------
### Add deploy script to package.json
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Update the scripts section to include a deployment command that builds the project and runs wrangler deploy.
```json
{
"scripts": {
"dev": "vite dev",
"build": "vite build && tsc --noEmit",
"start": "node .output/server/index.mjs",
// ============ 👇 add this line ============
"deploy": "npm run build && wrangler deploy"
}
}
```
--------------------------------
### createStartHandler - transformAssets Configuration
Source: https://tanstack.com/start/latest/docs/framework/react/guide/cdn-asset-urls.md
Configuration API for the transformAssets option in createStartHandler. Defines how asset URLs are transformed during server-side rendering, with support for static prefixes, dynamic callbacks, and per-request transforms with optional caching.
```APIDOC
## createStartHandler - transformAssets
### Description
Configures asset URL transformation for the TanStack Start server handler. Supports multiple forms for transforming asset URLs based on CDN requirements, with optional caching and per-request customization.
### Configuration Forms
#### String Prefix Form
Simplest form - prepends a static string to all asset URLs.
```
transformAssets: 'https://cdn.example.com'
```
#### Callback Form
Function that transforms each asset URL.
```
transformAssets: (asset) => string | { href, crossOrigin? } | Promise<...>
```
#### Object Form (Explicit Cache Control)
Advanced form with cache control and async factory support.
```
transformAssets: {
transform?: string | (asset) => string | { href, crossOrigin? } | Promise<...>,
createTransform?: (ctx) => (asset) => string | { href, crossOrigin? } | Promise<...>,
cache?: boolean,
warmup?: boolean
}
```
### Object Form Properties
#### transform
- **Type**: `string | (asset) => string | { href, crossOrigin? } | Promise<...>`
- **Required**: No (mutually exclusive with createTransform)
- **Description**: A string prefix or callback function. Same as the shorthand forms. The callback receives an asset object and returns a transformed URL string or object with href and optional crossOrigin properties.
#### createTransform
- **Type**: `(ctx: { warmup: true } | { warmup: false; request: Request }) => (asset) => string | { href, crossOrigin? } | Promise<...>`
- **Required**: No (mutually exclusive with transform)
- **Description**: Async factory function that runs once per manifest computation. Receives a context object indicating warmup mode or containing the current request. Returns a per-asset transform function. Use this for async operations like fetching CDN origins from services.
#### cache
- **Type**: `boolean`
- **Required**: No
- **Default**: `true`
- **Description**: Whether to cache the transformed manifest. When true, the transform runs once and is reused. When false, the manifest is deep-cloned and transformed on every request.
#### warmup
- **Type**: `boolean`
- **Required**: No
- **Default**: `false`
- **Description**: When true, warms up the cached manifest on server startup (production only). Useful for pre-computing transforms before handling requests.
### Asset Object Structure
The asset parameter passed to transform or createTransform callbacks contains:
- **kind**: `string` - Asset type (e.g., 'modulepreload')
- **url**: `string` - The asset URL to transform
### Transform Return Value
Transform functions can return:
- **string**: Simple URL string
- **object**: `{ href: string, crossOrigin?: string }` - URL with optional CORS attribute
- **Promise**: Any of the above wrapped in a Promise for async transforms
### Caching Behavior
| Form | Default Cache | Behavior |
|------|---|---|
| String prefix | true | Computed once, cached forever in production |
| Callback | true | Runs once on first request, cached forever in production |
| Object with cache: true (or omitted) | true | Same as callback form |
| Object with cache: false | false | Deep-clones base manifest and transforms on every request |
### Usage Recommendations
- Use **string prefix** for static CDN URLs
- Use **callback** for simple per-asset logic with static results
- Use **object form with cache: true** (default) for best performance with static transforms
- Use **object form with cache: false** only when transform depends on per-request data (e.g., geo-routing based on headers)
- Use **createTransform** for async operations that should run once per manifest computation
### Example: Per-Request Transform with Headers
```tsx
const handler = createStartHandler({
handler: defaultStreamHandler,
transformAssets: {
transform: ({ kind, url }) => {
const region = getRequest().headers.get('x-region') || 'us'
const cdnBase = region === 'eu'
? 'https://cdn-eu.example.com'
: 'https://cdn-us.example.com'
if (kind === 'modulepreload') {
return {
href: `${cdnBase}${url}`,
crossOrigin: 'anonymous',
}
}
return { href: `${cdnBase}${url}` }
},
cache: false,
},
})
```
### Example: Async Factory Transform
```ts
transformAssets: {
cache: false,
async createTransform(ctx) {
if (ctx.warmup) {
return ({ url }) => ({ href: url })
}
const region = ctx.request.headers.get('x-region') || 'us'
const cdnBase = await fetchCdnBaseForRegion(region)
return ({ kind, url }) => {
if (kind === 'modulepreload') {
return {
href: `${cdnBase}${url}`,
crossOrigin: 'anonymous',
}
}
return { href: `${cdnBase}${url}` }
}
},
}
```
```
--------------------------------
### Migrate Data Fetching from Async Components to Route Loaders
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Replace async server components with createFileRoute using a loader function. Access loaded data in the component using Route.useLoaderData().
```tsx
- export default async function Page() { // [!code --]
+ export const Route = createFileRoute('/')({ // [!code ++]
+ component: Page, // [!code ++]
+ loader: async () => { // [!code ++]
+ const res = await fetch('https://api.vercel.app/blog') // [!code ++]
+ return res.json() // [!code ++]
+ }, // [!code ++]
+ }) // [!code ++]
+ function Page() { // [!code ++]
- const data = await fetch('https://api.vercel.app/blog') // [!code --]
- const posts = await data.json() // [!code --]
+ const posts = Route.useLoaderData() // [!code ++]
return (
{posts.map((post) => (
{post.title}
))}
)
}
```
--------------------------------
### Server function wrappers with createServerFn
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-functions.md
Create .functions.ts files that export createServerFn wrappers. These wrap server-only helpers and can be safely imported anywhere, including client components.
```tsx
// users.functions.ts - Server functions
import { createServerFn } from '@tanstack/solid-start'
import { findUserById } from './users.server'
export const getUser = createServerFn({ method: 'GET' })
.inputValidator((data: { id: string }) => data)
.handler(async ({ data }) => {
return findUserById(data.id)
})
```
--------------------------------
### Access Request and Set Response in Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Demonstrates how to access the incoming request, read headers, and set response headers or status codes within a server function.
```tsx
import { createServerFn } from '@tanstack/react-start'
import {
getRequest,
getRequestHeader,
setResponseHeaders,
setResponseStatus,
} from '@tanstack/react-start/server'
export const getCachedData = createServerFn({ method: 'GET' }).handler(
async () => {
// Access the incoming request
const request = getRequest()
const authHeader = getRequestHeader('Authorization')
// Set response headers (e.g., for caching)
setResponseHeaders(
new Headers({
'Cache-Control': 'public, max-age=300',
'CDN-Cache-Control': 'max-age=3600, stale-while-revalidate=600',
}),
)
// Optionally set status code
setResponseStatus(200)
return fetchData()
},
)
```
--------------------------------
### Root Route Implementation with Authentication
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-auth
Defines the root route using createRootRoute with a beforeLoad hook to fetch user data on the server. It includes global layout components, SEO metadata, and session-aware navigation links.
```typescript
///
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { createServerFn } from '@tanstack/solid-start'
import { HydrationScript } from 'solid-js/web'
import type * as Solid from 'solid-js'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary.js'
import { NotFound } from '~/components/NotFound.js'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo.js'
import { useAppSession } from '~/utils/session.js'
const fetchUser = createServerFn({ method: 'GET' }).handler(async () => {
// We need to auth on the server so we have access to secure cookies
const session = await useAppSession()
if (!session.data.userEmail) {
return null
}
return {
email: session.data.userEmail,
}
})
export const Route = createRootRoute({
beforeLoad: async () => {
const user = await fetchUser()
return {
user,
}
},
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: Solid.JSX.Element }) {
const routeContext = Route.useRouteContext()
return (
{children}
)
}
```
--------------------------------
### Chained Middleware with Multiple Fetch Implementations
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Shows how multiple middlewares can provide fetch implementations, where the last middleware in the chain takes precedence. The second middleware's fetch overrides the first middleware's fetch.
```TypeScript
import { createMiddleware, createServerFn } from '@tanstack/solid-start'
import type { CustomFetch } from '@tanstack/solid-start'
const firstMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
const firstFetch: CustomFetch = (url, init) => {
const headers = new Headers(init?.headers)
headers.set('X-From', 'first-middleware')
return fetch(url, { ...init, headers })
}
return next({ fetch: firstFetch })
},
)
const secondMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
const secondFetch: CustomFetch = (url, init) => {
const headers = new Headers(init?.headers)
headers.set('X-From', 'second-middleware')
return fetch(url, { ...init, headers })
}
return next({ fetch: secondFetch })
},
)
const myServerFn = createServerFn()
.middleware([firstMiddleware, secondMiddleware])
.handler(async () => {
// Request will have X-From: 'second-middleware'
// because secondMiddleware's fetch overrides firstMiddleware's fetch
return { message: 'Hello' }
})
```
--------------------------------
### Root Document Layout with Navigation and Auth UI
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-clerk-basic
HTML document structure component providing the page layout, navigation links with active state styling, and conditional authentication UI using Clerk's SignedIn/SignedOut components. Includes TanStack Router devtools and script injection.
```TypeScript
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{children}
)
}
```
--------------------------------
### Server-Only Execution with createServerFn and createServerOnlyFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
Use createServerFn for RPC calls that client can invoke via network request, and createServerOnlyFn for utility functions that throw errors if called from client.
```tsx
import { createServerFn, createServerOnlyFn } from '@tanstack/react-start'
// RPC: Server execution, callable from client
const updateUser = createServerFn({ method: 'POST' })
.inputValidator((data: UserData) => data)
.handler(async ({ data }) => {
// Only runs on server, but client can call it
return await db.users.update(data)
})
// Utility: Server-only, client crashes if called
const getEnvVar = createServerOnlyFn(() => process.env.DATABASE_URL)
```
--------------------------------
### Create jokes.json data file
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/reading-writing-file
Creates an empty `jokes.json` file in the `src/data` directory to store joke data.
```bash
touch src/data/jokes.json
```
--------------------------------
### Server-side External API Integration with createServerFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Demonstrates how to securely fetch data from an external API on the server-side using `createServerFn`, protecting sensitive keys.
```typescript
// src/lib/external-api.ts
import { createServerFn } from '@tanstack/react-start'
// Server-side API calls (can use secret keys)
const fetchUserData = createServerFn()
.inputValidator(z.object({ userId: z.string() }))
.handler(async ({ data }) => {
const response = await fetch(
`${process.env.EXTERNAL_API_URL}/users/${data.userId}`,
{
headers: {
Authorization: `Bearer ${process.env.EXTERNAL_API_SECRET}`,
'Content-Type': 'application/json',
},
},
)
return response.json()
})
```
--------------------------------
### Environment-Specific Implementations with createIsomorphicFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
Define different implementations for server and client environments using createIsomorphicFn, allowing environment-specific logic to execute appropriately.
```tsx
import { createIsomorphicFn } from '@tanstack/react-start'
// Different implementation per environment
const getDeviceInfo = createIsomorphicFn()
.server(() => ({ type: 'server', platform: process.platform }))
.client(() => ({ type: 'client', userAgent: navigator.userAgent }))
```
--------------------------------
### SPA Redirects with Server Functions and Routes
Source: https://tanstack.com/start/latest/docs/framework/react/guide/spa-mode
Configure Netlify redirects to allow server functions and routes while catching remaining 404 requests for the SPA shell. Adjust paths if your server function base path or server routes differ from the defaults.
```plaintext
# Allow requests to /_serverFn/* to be routed through to the server (If you have configured your server function base path to be something other than /_serverFn, use that instead)
/_serverFn/* /_serverFn/:splat 200
# Allow any requests to /api/* to be routed through to the server (Server routes can be created at any path, so you must ensure that any server routes you want to use are under this path, or simply add additional redirects for each server route base you want to expose)
/api/* /api/:splat 200
# Catch all other 404 requests and rewrite them to the SPA shell
/* /_shell.html 200
```
--------------------------------
### Generate Tailwind and PostCSS Config Files (v3)
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/tailwind-integration.md
Generate the default Tailwind CSS and PostCSS configuration files for version 3.
```shell
npx tailwindcss init -p
```
--------------------------------
### Option B: Wrap Helper with createServerOnlyFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This snippet demonstrates using `createServerOnlyFn` to ensure a helper function (`leakyHelper`) only runs on the server. The server-only import `getUsers` is safely contained within its callback.
```ts
import { createServerOnlyFn } from '@tanstack/react-start'
import { getUsers } from './db/queries.server'
export const leakyHelper = createServerOnlyFn(() => {
return getUsers()
})
```
--------------------------------
### Option A: Split File for Server-Only Helpers (src/users-leaky.server.ts)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This snippet shows a separate file for a server-only helper (`leakyHelper`). This file should not be imported directly by client code to prevent import leaks.
```ts
// src/users-leaky.server.ts
import { getUsers } from './db/queries.server'
// Server-only helper; do not import this from client code
export function leakyHelper() {
return getUsers()
}
```
--------------------------------
### Create Markdown Processor Utility
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Define a utility function `renderMarkdown` that uses `unified` and various plugins to parse markdown, convert it to HTML, extract headings, and serialize the result.
```tsx
// src/utils/markdown.ts
import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkGfm from 'remark-gfm'
import remarkRehype from 'remark-rehype'
import rehypeRaw from 'rehype-raw'
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeStringify from 'rehype-stringify'
export type MarkdownHeading = {
id: string
text: string
level: number
}
export type MarkdownResult = {
markup: string
headings: Array
}
export async function renderMarkdown(content: string): Promise {
const headings: Array = []
const result = await unified()
.use(remarkParse) // Parse markdown
.use(remarkGfm) // Support GitHub Flavored Markdown
.use(remarkRehype, { allowDangerousHtml: true }) // Convert to HTML AST
.use(rehypeRaw) // Process raw HTML in markdown
.use(rehypeSlug) // Add IDs to headings
.use(rehypeAutolinkHeadings, {
behavior: 'wrap',
properties: { className: ['anchor'] },
})
.use(() => (tree) => {
// Extract headings for table of contents
const { visit } = require('unist-util-visit')
const { toString } = require('hast-util-to-string')
visit(tree, 'element', (node: any) => {
if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(node.tagName)) {
headings.push({
id: node.properties?.id || '',
text: toString(node),
level: parseInt(node.tagName.charAt(1), 10),
})
}
})
})
.use(rehypeStringify) // Serialize to HTML string
.process(content)
return {
markup: String(result),
headings
}
}
```
--------------------------------
### Handle FormData with createServerFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Demonstrates how to process FormData submissions using `createServerFn` by validating the input and extracting fields.
```tsx
export const submitForm = createServerFn({ method: 'POST' })
.inputValidator((data) => {
if (!(data instanceof FormData)) {
throw new Error('Expected FormData')
}
return {
name: data.get('name')?.toString() || '',
email: data.get('email')?.toString() || '',
}
})
.handler(async ({ data }) => {
// Process form data
return { success: true }
})
```
--------------------------------
### Root Component with Meta Tags and Links Configuration
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-solid-query
Configures the root route with meta tags for charset and viewport, SEO metadata, favicon links, and error/not-found components. The meta array uses the spread operator with an seo() helper function.
```TypeScript
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
```
--------------------------------
### Bundle components using renderServerComponent
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Use this approach for simple components that share data but do not require slots. It fetches shared data once and returns multiple renderable components.
```tsx
const getPageLayout = createServerFn().handler(async () => {
// Fetch shared data once
const user = await db.users.getCurrent()
const config = await db.config.get()
// Create multiple components that share this data
const [Header, Content, Footer] = await Promise.all([
renderServerComponent(
,
),
renderServerComponent(
Welcome, {user.name}
,
),
renderServerComponent(
,
),
])
return { Header, Content, Footer }
})
export const Route = createFileRoute('/dashboard')({
loader: async () => await getPageLayout(),
component: DashboardPage,
})
function DashboardPage() {
const { Header, Content, Footer } = Route.useLoaderData()
return (
<>
{Header}
{Content}
{Footer}
>
)
}
```
--------------------------------
### Define server-side middleware logic
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Use the .server method to execute logic before nested middleware and provide context to the next step in the chain.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const loggingMiddleware = createMiddleware().server(
({ next, context, request }) => {
return next()
},
)
```
--------------------------------
### Configure import protection deny rules in vite.config.ts
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/import-protection.md
Set up environment-specific deny rules to block npm packages and file patterns from client and server bundles. Use specifiers for npm packages and files for glob patterns.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
export default defineConfig({
plugins: [
tanstackStart({
importProtection: {
client: {
// Block specific npm packages from the client bundle
specifiers: ['@prisma/client', 'bcrypt'],
// Block files in a custom directory
files: ['**/db/**'],
},
server: {
// Block browser-only libraries from the server
specifiers: ['localforage'],
},
},
}),
],
})
```
--------------------------------
### Access Runtime Server Variables on the Client
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Use createServerFn to fetch server-side environment variables and pass them to the client via a route loader.
```tsx
const getRuntimeVar = createServerFn({ method: 'GET' }).handler(() => {
return process.env.MY_RUNTIME_VAR // notice `process.env` on the server, and no `VITE_` prefix
})
export const Route = createFileRoute('/')({
loader: async () => {
const foo = await getRuntimeVar()
return { foo }
},
component: RouteComponent,
})
function RouteComponent() {
const { foo } = Route.useLoaderData()
// ... use your variable however you want
}
```
--------------------------------
### Integrate Shiki for Syntax Highlighting
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Use the codeToHtml function from Shiki to generate themed HTML for code blocks during markdown processing.
```tsx
// src/utils/markdown.ts
import { codeToHtml } from 'shiki'
// Process code blocks after parsing
export async function highlightCode(
code: string,
language: string,
): Promise {
return codeToHtml(code, {
lang: language,
themes: {
light: 'github-light',
dark: 'tokyo-night',
},
})
}
```
--------------------------------
### Build a Solid.js Form Component for Server Function Interaction
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/reading-writing-file.md
Create a form component using Solid.js signals to manage state and trigger server functions on submission. Note that the handleSubmit function implementation is omitted in the source snippet.
```tsx
// src/components/JokeForm.tsx
import { createSignal } from 'solid'
import { useRouter } from '@tanstack/solid-router'
import { addJoke } from '../serverActions/jokesActions'
export function JokeForm() {
const router = useRouter()
const [question, setQuestion] = createSignal('')
const [answer, setAnswer] = createSignal('')
const [isSubmitting, setIsSubmitting] = createSignal(false)
const [error, setError] = createSignal(null)
return (
)
}
```
--------------------------------
### Configuring import protection behavior per environment
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
Set different import protection behaviors for development (`mock`) and production (`error`) builds within your Vite configuration.
```typescript
importProtection: {
behavior: {
dev: 'mock',
build: 'error',
},
}
```
--------------------------------
### Integration Test Authentication Flow with SolidJS Testing Library
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/authentication.md
Shows how to perform an integration test for an authentication flow, verifying that unauthenticated users are redirected to the login page when accessing protected routes.
```tsx
// __tests__/auth-flow.test.tsx
import { render, screen, fireEvent, waitFor } from '@solidjs/testing-library'
import { RouterProvider, createMemoryHistory } from '@tanstack/solid-router'
import { router } from '../router'
describe('Authentication Flow', () => {
it('should redirect to login when accessing protected route', async () => {
const history = createMemoryHistory()
history.push('/dashboard') // Protected route
render()
await waitFor(() => {
expect(screen.getByText('Login')).toBeInTheDocument()
})
})
})
```
--------------------------------
### Progress Middleware Chain with next()
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Call the `next()` function in the `.server()` method to execute the next middleware in the chain. This allows short-circuiting, passing data between middleware, and accessing results from nested middleware.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const loggingMiddleware = createMiddleware().server(async ({ next }) => {
const result = await next() // <-- This will execute the next middleware in the chain
return result
})
```
--------------------------------
### Import CSS File in Root Route with Vite Query
Source: https://tanstack.com/start/latest/docs/framework/react/guide/tailwind-integration
Import the CSS file in __root.tsx using the ?url query parameter and add the triple slash Vite client type reference directive.
```typescript
// src/routes/__root.tsx
///
// other imports...
import appCss from '../styles/app.css?url'
export const Route = createRootRoute({
head: () => ({
meta: [
// your meta tags and site config
],
links: [{ rel: 'stylesheet', href: appCss }],
// other head config
}),
component: RootComponent,
})
```
--------------------------------
### Root Route Configuration Fragment
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-cloudflare
Defines global assets such as favicons, web manifests, and custom scripts within the root route configuration.
```typescript
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
scripts: [
{
src: '/customScript.js',
type: 'text/javascript',
},
],
}),
errorComponent: DefaultCatchBoundary,
notFoundComponent: () => ,
shellComponent: RootDocument,
})
```
--------------------------------
### Composite Server Component Pattern with Slots
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Use createCompositeComponent to create a server component that accepts client-provided content via slots. Render with CompositeComponent and pass children or other slot content from the client.
```tsx
import { createFileRoute } from '@tanstack/react-router'
import { createServerFn } from '@tanstack/react-start'
import {
CompositeComponent,
createCompositeComponent,
} from '@tanstack/react-start/rsc'
const getCard = createServerFn().handler(async () => {
const src = await createCompositeComponent(
(props: { children?: React.ReactNode }) => (
Server-rendered header
{props.children}
),
)
return { src }
})
export const Route = createFileRoute('/')( {
loader: async () => ({
Card: await getCard(),
}),
component: HomePage,
})
function HomePage() {
const { Card } = Route.useLoaderData()
return (
)
}
```
--------------------------------
### Environment-Specific Logging with createIsomorphicFn
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
Use createIsomorphicFn to define separate logging logic for server and client environments, supporting both development and production formats.
```tsx
// utils/logger.ts
import { createIsomorphicFn } from '@tanstack/solid-start'
type LogLevel = 'debug' | 'info' | 'warn' | 'error'
const logger = createIsomorphicFn()
.server((level: LogLevel, message: string, data?: any) => {
const timestamp = new Date().toISOString()
if (process.env.NODE_ENV === 'development') {
// Development: Detailed console logging
console[level](`[${timestamp}] [${level.toUpperCase()}]`, message, data)
} else {
// Production: Structured JSON logging
console.log(
JSON.stringify({
timestamp,
level,
message,
data,
service: 'tanstack-start',
environment: process.env.NODE_ENV,
}),
)
}
})
.client((level: LogLevel, message: string, data?: any) => {
if (process.env.NODE_ENV === 'development') {
console[level](`[CLIENT] [${level.toUpperCase()}]`, message, data)
} else {
// Production: Send to analytics service
// analytics.track('client_log', { level, message, data })
}
})
// Usage anywhere in your app
export { logger }
// Example usage
const fetchUserData = createServerFn().handler(async ({ data: userId }) => {
logger('info', 'Fetching user data', { userId })
try {
const user = await db.users.findUnique({ where: { id: userId } })
logger('info', 'User data fetched successfully', { userId })
return user
} catch (error) {
logger('error', 'Failed to fetch user data', {
userId,
error: error.message,
})
throw error
}
})
```
--------------------------------
### Create Request Middleware
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Create request middleware using `createMiddleware()` to customize behavior of any server request, including server routes, SSR, and server functions. The `type` property defaults to 'request' and can be omitted.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
```
--------------------------------
### Root Route Configuration with Server Data Fetching
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-auth
Defines the root route with server-side data fetching, head metadata configuration, error/not-found handlers, and main component. The `loader` function fetches user data server-side before rendering.
```TypeScript
const user = await fetchUser()
return {
user,
}
},
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
```
--------------------------------
### Isomorphic Function with No Environment-Specific Implementation
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-functions.md
Demonstrates `createIsomorphicFn` without any `.server()` or `.client()` implementations, resulting in a no-op function.
```tsx
import { createIsomorphicFn } from '@tanstack/react-start'
const noImplementation = createIsomorphicFn()
const noop = noImplementation()
// ℹ️ On both **client** and **server**, it is no-op (returns `undefined`)
```
--------------------------------
### Configure Static NODE_ENV Replacement in Vite
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Enable or disable static replacement of NODE_ENV in the server build via the tanstackStart plugin configuration.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
tanstackStart({
server: {
build: {
// Replace process.env.NODE_ENV at build time (default: true)
staticNodeEnv: true,
},
},
}),
viteReact(),
],
})
```
--------------------------------
### Async Per-Manifest Asset Transform using 'createTransform'
Source: https://tanstack.com/start/latest/docs/framework/react/guide/cdn-asset-urls.md
This snippet demonstrates using `createTransform` for async operations that need to run once per manifest computation, such as fetching a CDN origin from a service. It returns a per-asset transform function.
```ts
transformAssets: {
cache: false,
async createTransform(ctx) {
if (ctx.warmup) {
return ({ url }) => ({ href: url })
}
const region = ctx.request.headers.get('x-region') || 'us'
const cdnBase = await fetchCdnBaseForRegion(region)
return ({ kind, url }) => {
if (kind === 'modulepreload') {
return {
href: `${cdnBase}${url}`,
crossOrigin: 'anonymous',
}
}
return { href: `${cdnBase}${url}` }
}
},
}
```
--------------------------------
### Dynamic Path Parameters in Server Routes
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Define dynamic segments in filenames using the $ prefix to access them via the params object in server handlers.
```ts
// routes/users/$id.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/users/$id')({
server: {
handlers: {
GET: async ({ params }) => {
const { id } = params
return new Response(`User ID: ${id}`)
},
},
},
})
// Visit /users/123 to see the response
// User ID: 123
```
```ts
// routes/users/$id/posts/$postId.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/users/$id/posts/$postId')({
server: {
handlers: {
GET: async ({ params }) => {
const { id, postId } = params
return new Response(`User ID: ${id}, Post ID: ${postId}`)
},
},
},
})
// Visit /users/123/posts/456 to see the response
// User ID: 123, Post ID: 456
```
--------------------------------
### Deferred Component Loading with React.use() and Suspense
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Return promises for multiple server components from a server function, then render each with Suspense as it resolves. Faster components display before slower ones complete, avoiding blocking on the slowest query.
```tsx
import { Suspense, use } from 'react'
const getDashboardBundle = createServerFn().handler(() => ({
// Fast - resolves in ~100ms
QuickStats: (async () => {
const stats = await cache.getStats() // Fast cache hit
return renderServerComponent()
})(),
// Medium - resolves in ~500ms
RecentActivity: (async () => {
const activity = await db.activity.getRecent()
return renderServerComponent()
})(),
// Slow - resolves in ~2000ms
Analytics: (async () => {
const data = await analytics.computeMetrics() // Expensive query
return renderServerComponent()
})(),
}))
export const Route = createFileRoute('/dashboard')({
loader: () => getDashboardBundle(),
component: DashboardPage,
})
function DashboardPage() {
const { QuickStats, RecentActivity, Analytics } = Route.useLoaderData()
return (
}>
}>
}>
)
}
function Deferred({ promise }: { promise: Promise }) {
const Renderable = use(promise)
return <>{Renderable}>
}
```
--------------------------------
### Root Route and Document Component Implementation
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-supabase-basic
Defines the root route configuration with SEO metadata, global stylesheets, and the base HTML layout including navigation and TanStack Router devtools.
```tsx
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: React.ReactNode }) {
const { user } = Route.useRouteContext()
return (
Home
{' '}
Posts
{user ? (
<>
{user.email}
Logout
>
) : (
Login
)}
{children}
)
}
```
--------------------------------
### Router Links in Server Components
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Demonstrates how to use TanStack Router's Link component within server components. The link is serialized and hydrates on the client for client-side navigation, allowing dynamic page navigation from server-rendered content.
```APIDOC
## Router Links in Server Components
### Description
Use TanStack Router's `Link` component inside server components for client-side navigation. Links are serialized and hydrate on the client.
### Import
```tsx
import { Link } from '@tanstack/react-router'
```
### Component Props
- **to** (string) - Required - The target route path, supports dynamic segments like `/pages/$pageId`
- **params** (object) - Optional - Route parameters object to populate dynamic segments
- **children** (ReactNode) - Required - Link text or content
- **key** (string) - Required - Unique identifier for list rendering
### Usage Example
```tsx
const getNavigation = createServerFn().handler(async () => {
const pages = await db.pages.list()
return renderServerComponent(
,
)
})
```
```
--------------------------------
### Solid.js Navigation Bar with Authentication Context
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-authjs
Accesses session data via Route.useRouteContext() to display user info or a sign-in link. Uses the Show component for conditional rendering based on the session state.
```tsx
{children}
)
}
function NavBar() {
const routeContext = Route.useRouteContext()
return (
)
}
```
--------------------------------
### Implement Progressive Enhancement with ClientOnly
Source: https://tanstack.com/start/latest/docs/framework/react/guide/code-execution-patterns.md
Wrap client-specific components to provide server-side fallbacks, ensuring functionality without JavaScript.
```tsx
// Component works without JS, enhanced with JS
function SearchForm() {
const [query, setQuery] = useState('')
return (
)
}
```
--------------------------------
### Handle Basic Errors in Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Shows how to throw and catch errors from a server function. Errors are automatically serialized to the client.
```tsx
import { createServerFn } from '@tanstack/react-start'
export const riskyFunction = createServerFn().handler(async () => {
if (Math.random() > 0.5) {
throw new Error('Something went wrong!')
}
return { success: true }
})
// Errors are serialized to the client
try {
await riskyFunction()
} catch (error) {
console.log(error.message) // "Something went wrong!"
}
```
--------------------------------
### Implement Custom Server Handler with defineHandlerCallback
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-entry-point.md
This snippet illustrates how to define a custom server handler using defineHandlerCallback to add custom logic before invoking the default stream handler.
```tsx
// src/server.ts
import {
createStartHandler,
defaultStreamHandler,
defineHandlerCallback
} from '@tanstack/solid-start/server'
import { createServerEntry } from '@tanstack/solid-start/server-entry'
const customHandler = defineHandlerCallback((ctx) => {
// add custom logic here
return defaultStreamHandler(ctx)
})
const fetch = createStartHandler(customHandler)
export default createServerEntry({
fetch
})
```
--------------------------------
### Upgrade React and ReactDOM for Bun Deployment
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Upgrade `react` and `react-dom` packages to version 19.0.0 or higher to ensure compatibility with Bun-specific deployment guidelines.
```sh
bun install react@19 react-dom@19
```
--------------------------------
### Configure secure session settings
Source: https://tanstack.com/start/latest/docs/framework/react/guide/authentication.md
Set up session configuration with HTTPS-only cookies in production, CSRF protection via sameSite, XSS protection with httpOnly, and appropriate session expiration.
```tsx
// Use secure session configuration
export function useAppSession() {
return useSession({
name: 'app-session',
password: process.env.SESSION_SECRET!, // 32+ characters
cookie: {
secure: process.env.NODE_ENV === 'production', // HTTPS only in production
sameSite: 'lax', // CSRF protection
httpOnly: true, // XSS protection
maxAge: 7 * 24 * 60 * 60, // 7 days
},
})
}
```
--------------------------------
### Authentication Context for State Sharing
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/authentication.md
Create an authentication context using Solid.js to share user state and loading status across the application. Provides useAuth hook that must be used within AuthProvider wrapper.
```typescript
// contexts/auth.tsx
import { createContext, useContext } from 'solid-js'
import { useServerFn } from '@tanstack/solid-start'
import { getCurrentUserFn } from '../server/auth'
type User = {
id: string
email: string
role: string
}
type AuthContextType = {
user: User | null
isLoading: boolean
refetch: () => void
}
const AuthContext = createContext(undefined)
export function AuthProvider(props) {
const { data: user, isLoading, refetch } = useServerFn(getCurrentUserFn)
return (
{props.children}
)
}
export function useAuth() {
const context = useContext(AuthContext)
if (!context) {
throw new Error('useAuth must be used within AuthProvider')
}
return context
}
```
--------------------------------
### Enable SPA Mode in Vite Config
Source: https://tanstack.com/start/latest/docs/framework/react/guide/spa-mode
Add the spa configuration object to the tanstackStart plugin options to enable SPA mode for your application.
```typescript
// vite.config.ts
export default defineConfig({
plugins: [
tanstackStart({
spa: {
enabled: true,
},
}),
],
})
```
--------------------------------
### Isomorphic Functions and Route Loaders
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
Utility functions and route loaders run on both server and client by default. The formatPrice function executes in both environments, and route loaders run during SSR and client-side navigation.
```tsx
// ✅ This runs on BOTH server and client
function formatPrice(price: number) {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(price)
}
// ✅ Route loaders are ISOMORPHIC
export const Route = createFileRoute('/products')({
loader: async () => {
// This runs on server during SSR AND on client during navigation
const response = await fetch('/api/products')
return response.json()
},
})
```
--------------------------------
### Migrate Next.js Server Route Handlers to TanStack
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Replace Next.js route handlers with createFileRoute and define handlers within a server configuration object.
```ts
- export async function GET() { // [!code --]
+ export const Route = createFileRoute('/api/hello')({ // [!code ++]
+ server: { // [!code ++]
+ handlers: { // [!code ++]
+ GET: async () => { // [!code ++]
+ return Response.json("Hello, World!")
+ } // [!code ++]
+ } // [!code ++]
+ } // [!code ++]
+ }) // [!code ++]
```
--------------------------------
### Add Organization and Website Schema to Root Route
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
Implements JSON-LD structured data in the root route to provide site-wide context about the organization and website. This schema helps search engines and AI systems understand the site's purpose, branding, and social presence. The schema includes organization details, logo, and social media links.
```tsx
// src/routes/__root.tsx
export const Route = createRootRoute({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
],
scripts: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'My App',
url: 'https://myapp.com',
publisher: {
'@type': 'Organization',
name: 'My Company',
url: 'https://myapp.com',
logo: 'https://myapp.com/logo.png',
sameAs: [
'https://twitter.com/mycompany',
'https://github.com/mycompany',
],
},
}),
},
],
}),
component: RootComponent,
})
```
--------------------------------
### Authenticate with Wrangler
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Login to Cloudflare account using Wrangler CLI. Use pnpm dlx variant if using pnpm package manager.
```bash
npx wrangler login
```
```bash
pnpm dlx wrangler login
```
--------------------------------
### Monitor Cache Hit Rates with Middleware
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Create server middleware to log cache status headers from the CDN. Useful for tracking cache performance and debugging cache misses.
```tsx
const cacheMonitoringMiddleware = createMiddleware().server(
async ({ next }) => {
const result = await next()
// Log cache status (from CDN headers)
console.log('Cache Status:', result.response.headers.get('cf-cache-status'))
return result
},
)
```
--------------------------------
### Configure Cache Headers with Vary Parameters
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Set Cache-Control and Vary headers in route definitions to cache content by query parameters. Use this when content varies based on query strings like search terms or filters.
```tsx
export const Route = createFileRoute('/search')({
headers: () => ({
'Cache-Control': 'public, max-age=300',
Vary: 'Accept, Accept-Encoding',
}),
})
```
--------------------------------
### Partial Isomorphic Function (Client-only) with createIsomorphicFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-functions.md
Illustrates an isomorphic function configured to run only on the client. It returns `undefined` when called on the server.
```tsx
import { createIsomorphicFn } from '@tanstack/react-start'
const clientImplementationOnly = createIsomorphicFn().client(() => 'client')
const client = clientImplementationOnly()
// ℹ️ On the **server**, it is no-op (returns `undefined`)
// ℹ️ On the **client**, it returns `'client'`.
```
--------------------------------
### SolidJS TanStack Router Root Route Definition
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-cloudflare
Defines the application's root route using `createRootRoute`, configuring head content (meta, links, scripts), error boundaries, and the main `RootDocument` shell component with navigation links.
```typescript
///
import {
HeadContent,
Link,
Scripts,
createRootRoute,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { HydrationScript } from 'solid-js/web'
import type * as Solid from 'solid-js'
import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary'
import { NotFound } from '~/components/NotFound'
import appCss from '~/styles/app.css?url'
import { seo } from '~/utils/seo'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack React Framework',
description: `TanStack Start is a type-safe, client-first, full-stack React framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
scripts: [
{
src: '/customScript.js',
type: 'text/javascript',
},
],
}),
errorComponent: DefaultCatchBoundary,
notFoundComponent: () => ,
shellComponent: RootDocument,
})
function RootDocument({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Implementing Feature Flags in TanStack SolidStart
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-variables.md
Define feature flags using `import.meta.env` for conditional rendering. Access flags from a central configuration object.
```typescript
// src/config/features.ts
export const featureFlags = {
enableNewDashboard: import.meta.env.VITE_ENABLE_NEW_DASHBOARD === 'true',
enableAnalytics: import.meta.env.VITE_ENABLE_ANALYTICS === 'true',
debugMode: import.meta.env.VITE_DEBUG_MODE === 'true',
}
// Usage in components
export function Dashboard() {
if (featureFlags.enableNewDashboard) {
return
}
return
}
```
--------------------------------
### Wildcard and Splat Parameters
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
Use a trailing $ in the filename to capture all remaining path segments into the _splat parameter.
```ts
// routes/file/$.ts
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/file/$')({
server: {
handlers: {
GET: async ({ params }) => {
const { _splat } = params
return new Response(`File: ${_splat}`)
},
},
},
})
// Visit /file/hello.txt to see the response
// File: hello.txt
```
--------------------------------
### Integrate React Server Components with TanStack Query
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Use `useSuspenseQuery` and `ensureQueryData` to fetch and cache server components. Ensure `structuralSharing: false` to prevent merging RSC values.
```tsx
import { useSuspenseQuery, useQueryClient } from '@tanstack/react-query'
const postQueryOptions = (postId: string) => ({
queryKey: ['post', postId],
structuralSharing: false, // Required - RSC values must not be merged
queryFn: () => getPost({ data: { postId } }),
staleTime: 5 * 60 * 1000,
})
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ context, params }) => {
// Prefetch during SSR - data reused on client without refetch
await context.queryClient.ensureQueryData(postQueryOptions(params.postId))
},
component: PostPage,
})
function PostPage() {
const { postId } = Route.useParams()
const queryClient = useQueryClient()
const { data } = useSuspenseQuery(postQueryOptions(postId))
const handleRefresh = () => {
// Manually refetch the RSC
queryClient.refetchQueries({ queryKey: ['post', postId] })
}
return
}
```
--------------------------------
### Differentiating RPC and Server-Only Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
createServerFn enables RPC calls from the client to the server, while createServerOnlyFn restricts execution strictly to the server, throwing an error if called from the client.
```tsx
// createServerFn: RPC pattern - server execution, client callable
const fetchUser = createServerFn().handler(async () => await db.users.find())
// Usage from client component:
const user = await fetchUser() // ✅ Network request
// createServerOnlyFn: Crashes if called from client
const getSecret = createServerOnlyFn(() => process.env.SECRET)
// Usage from client:
const secret = getSecret() // ❌ Throws error
```
--------------------------------
### Client-Only Components with ClientOnly and NoHydration
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hydration-errors.md
Use ClientOnly or Solid's NoHydration to skip server-side rendering for components that depend on client-only APIs or inherently dynamic content. ClientOnly accepts a fallback; NoHydration renders only on the client.
```tsx
import { ClientOnly } from '@tanstack/solid-router'
import { NoHydration } from 'solid-js/web'
—}>
```
--------------------------------
### Root Route Configuration with Error and Not Found Handlers
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-clerk-basic
Configure the root route with manifest and favicon metadata, error boundary component, and not-found page handler. The errorComponent wraps errors in RootDocument context, while notFoundComponent displays a custom 404 page.
```TypeScript
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
```
```TypeScript
errorComponent: (props) => {
return (
)
},
```
```TypeScript
notFoundComponent: () => ,
```
```TypeScript
component: RootComponent,
```
--------------------------------
### Use Vite `experimental.renderBuiltUrl` for Direct Asset URLs
Source: https://tanstack.com/start/latest/docs/framework/react/guide/cdn-asset-urls.md
Implement `experimental.renderBuiltUrl` in `vite.config.ts` to customize how Vite generates URLs for directly imported assets. This allows you to prepend a CDN origin or use relative paths for specific asset types.
```ts
// vite.config.ts
export default defineConfig({
experimental: {
renderBuiltUrl(filename, { hostType }) {
if (hostType === 'js') {
return { relative: true }
}
return `https://cdn.example.com/${filename}`
}
}
})
```
--------------------------------
### Environment-Specific Observability Configuration
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Configure different observability strategies for development and production environments. Disables metrics in development to reduce noise while enabling full instrumentation in production.
```typescript
// Different strategies per environment
const observabilityConfig = {
development: {
logLevel: 'debug',
enableTracing: true,
enableMetrics: false, // Too noisy in dev
},
production: {
logLevel: 'warn',
enableTracing: true,
enableMetrics: true,
enableAlerting: true,
},
}
```
--------------------------------
### Configure `transformAssets` Warmup for CDN Caching
Source: https://tanstack.com/start/latest/docs/framework/react/guide/cdn-asset-urls.md
Set `warmup: true` within `transformAssets` when `cache: true` to pre-compute the manifest at server startup, reducing first-request latency. This setting is ignored in development mode or when caching is disabled.
```ts
transformAssets: {
transform: process.env.CDN_ORIGIN || '',
cache: true,
warmup: true,
}
```
--------------------------------
### Attach middleware to server function
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Pass a middleware array to the `middleware` property of `createServerFn` to wrap a specific server function. The middleware will execute before the handler.
```tsx
import { createServerFn } from '@tanstack/solid-start'
import { loggingMiddleware } from './middleware'
const fn = createServerFn()
.middleware([loggingMiddleware])
.handler(async () => {
//...
})
```
--------------------------------
### Integrate TanStack Query with route loaders
Source: https://tanstack.com/start/latest/docs/framework/react/comparison
Use queryOptions to define reusable query configuration and ensureQueryData in the loader to pre-populate the cache. The component then accesses the same cached data automatically.
```TypeScript
import { queryOptions } from '@tanstack/react-query'
const postQueryOptions = (postId: string) =>
queryOptions({
queryKey: ['post', postId],
queryFn: () => fetchPost(postId),
})
export const Route = createFileRoute('/posts/$postId')({
loader: ({ context, params }) =>
context.queryClient.ensureQueryData(postQueryOptions(params.postId)),
})
function Post() {
const { postId } = Route.useParams()
const { data } = useQuery(postQueryOptions(postId))
// Automatically uses cached data from loader
}
```
--------------------------------
### Create Request and Response Logging Middleware
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Use server-side middleware to log request methods, URLs, status codes, and execution durations for specific routes.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const requestLogger = createMiddleware().server(async ({ request, next }) => {
const startTime = Date.now()
const timestamp = new Date().toISOString()
console.log(`[${timestamp}] ${request.method} ${request.url} - Starting`)
try {
const result = await next()
const duration = Date.now() - startTime
console.log(
`[${timestamp}] ${request.method} ${request.url} - ${result.response.status} (${duration}ms)`,
)
return result
} catch (error) {
const duration = Date.now() - startTime
console.error(
`[${timestamp}] ${request.method} ${request.url} - Error (${duration}ms):`,
error,
)
throw error
}
})
// Apply to all server routes
export const Route = createFileRoute('/api/users')({
server: {
middleware: [requestLogger],
handlers: {
GET: async () => {
return Response.json({ users: await getUsers() })
},
},
},
})
```
--------------------------------
### Configure Vite `base` for CDN Client-Side Navigation
Source: https://tanstack.com/start/latest/docs/framework/react/guide/cdn-asset-urls.md
Set `base: ''` in your `vite.config.ts` to ensure client-side navigation chunks are loaded from the CDN. This generates relative import paths that resolve against the CDN origin when the entry module is loaded from the CDN.
```ts
// vite.config.ts
export default defineConfig({
base: '',
// ... plugins, etc.
})
```
--------------------------------
### Structure Documentation with Hierarchical Headings
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
React component demonstrating proper heading hierarchy (h1, h2, h3) and semantic section elements for documentation pages. This structure helps AI systems understand content organization and extract information based on logical grouping.
```tsx
function DocumentationPage() {
return (
Getting Started with TanStack Start
Installation
Install TanStack Start using npm...
Prerequisites
You'll need Node.js 18 or later...
Configuration
Configure your app in vite.config.ts...
)
}
```
--------------------------------
### Throw Not Found Errors in Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Explains how to throw a `notFound` error from a server function when a requested resource is not found.
```tsx
import { createServerFn } from '@tanstack/react-start'
import { notFound } from '@tanstack/react-router'
export const getPost = createServerFn()
.inputValidator((data: { id: string }) => data)
.handler(async ({ data }) => {
const post = await db.findPost(data.id)
if (!post) {
throw notFound()
}
return post
})
```
--------------------------------
### Implementing Server-Only Functions and RPCs in TSX
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/execution-model.md
Use createServerFn for RPC calls that the client can trigger, and createServerOnlyFn for utilities that must never run on the client. Client-side calls to server-only utilities will result in an error.
```tsx
import { createServerFn, createServerOnlyFn } from '@tanstack/solid-start'
// RPC: Server execution, callable from client
const updateUser = createServerFn({ method: 'POST' })
.inputValidator((data: UserData) => data)
.handler(async ({ data }) => {
// Only runs on server, but client can call it
return await db.users.update(data)
})
// Utility: Server-only, client crashes if called
const getEnvVar = createServerOnlyFn(() => process.env.DATABASE_URL)
```
--------------------------------
### Apply middleware to server routes
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Middleware can be applied globally to all route methods or targeted to specific handlers using the createHandlers utility.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
export const Route = createFileRoute('/foo')({
server: {
middleware: [loggingMiddleware],
handlers: {
GET: () => {
//...
},
POST: () => {
//...
},
},
},
})
```
```tsx
import { createMiddleware } from '@tanstack/solid-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
export const Route = createFileRoute('/foo')({
server: {
handlers: ({ createHandlers }) =>
createHandlers({
GET: {
middleware: [loggingMiddleware],
handler: () => {
//...
},
},
}),
},
})
```
--------------------------------
### Implement Cache Headers via Middleware or Route Config
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Compare using middleware for shared API caching logic versus using the headers property for direct page route configuration.
```tsx
// routes/api/products/$productId.ts
import { createFileRoute } from '@tanstack/react-router'
import { createMiddleware } from '@tanstack/react-start'
const cacheMiddleware = createMiddleware().server(async ({ next }) => {
const result = await next()
// Add cache headers to the response
result.response.headers.set(
'Cache-Control',
'public, max-age=3600, stale-while-revalidate=86400',
)
return result
})
export const Route = createFileRoute('/api/products/$productId')({
server: {
middleware: [cacheMiddleware],
handlers: {
GET: async ({ params }) => {
const product = await db.products.findById(params.productId)
return Response.json({ product })
},
},
},
})
```
```tsx
// routes/blog/posts/$postId.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/blog/posts/$postId')({
loader: async ({ params }) => {
const post = await fetchPost(params.postId)
return { post }
},
headers: () => ({
'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400',
}),
})
```
--------------------------------
### Root Document and Router Configuration
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-basic-nitro
Defines the root HTML structure and router configuration, including meta tags, external scripts, and a navigation layout with active link styling.
```tsx
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
scripts: [
{
src: '/customScript.js',
type: 'text/javascript',
},
],
}),
errorComponent: DefaultCatchBoundary,
notFoundComponent: () => ,
shellComponent: RootDocument,
})
function RootDocument({ children }: { children: Solid.JSX.Element }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Partial Isomorphic Function (Server-only) with createIsomorphicFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-functions.md
Shows an isomorphic function configured to run only on the server. It returns `undefined` when called on the client.
```tsx
import { createIsomorphicFn } from '@tanstack/react-start'
const serverImplementationOnly = createIsomorphicFn().server(() => 'server')
const server = serverImplementationOnly()
// ℹ️ On the **server**, it returns `'server'`.
// ℹ️ On the **client**, it is no-op (returns `undefined`)
```
--------------------------------
### Protect Routes with beforeLoad in TanStack Solid Router
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/authentication.md
Use beforeLoad to verify user authentication before rendering protected routes. Redirects unauthenticated users to login with the original location preserved for post-login redirect.
```tsx
// routes/_authed.tsx - Layout route for protected pages
import { createFileRoute, redirect } from '@tanstack/solid-router'
import { getCurrentUserFn } from '../server/auth'
export const Route = createFileRoute('/_authed')({
beforeLoad: async ({ location }) => {
const user = await getCurrentUserFn()
if (!user) {
throw redirect({
to: '/login',
search: { redirect: location.href },
})
}
// Pass user to child routes
return { user }
},
})
```
```tsx
// routes/_authed/dashboard.tsx - Protected route
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/_authed/dashboard')({
component: DashboardComponent,
})
function DashboardComponent() {
const context = Route.useRouteContext()
return (
Welcome, {context().user.email}!
{/* Dashboard content */}
)
}
```
--------------------------------
### Root Document HTML Structure
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-workos
Server-side HTML document wrapper that renders the React tree with head content and scripts. Accepts children as a prop and provides the base HTML structure for the application.
```TypeScript
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
return (
{children}
);
}
```
--------------------------------
### Statically import server functions in client components
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Static imports are safe as the build process replaces server implementations with RPC stubs for the client bundle.
```tsx
// ✅ Safe - build process handles environment shaking
import { getUser } from '~/utils/users.functions'
function UserProfile({ id }) {
const { data } = useQuery({
queryKey: ['user', id],
queryFn: () => getUser({ data: { id } }),
})
}
```
--------------------------------
### Client Entry Point with Error Boundary
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/client-entry-point.md
Wrap the client application in an ErrorBoundary to prevent the entire app from crashing on client-side runtime errors.
```tsx
// src/client.tsx
import { StartClient } from '@tanstack/solid-start/client'
import { hydrate } from 'solid-js/web'
import { ErrorBoundary } from './components/ErrorBoundary'
hydrate(
() => (
),
document.body,
)
```
--------------------------------
### Root Route and Server Function for Supabase Auth
Source: https://tanstack.com/start/latest/docs/framework/solid/examples/start-supabase-basic
Uses createServerFn to fetch the current user from Supabase and createRootRoute to provide user context and SEO tags.
```tsx
///
import {
HeadContent,
Link,
Outlet,
Scripts,
createRootRoute,
} from '@tanstack/solid-router'
import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
import { createServerFn } from '@tanstack/solid-start'
import { HydrationScript } from 'solid-js/web'
import { DefaultCatchBoundary } from '../components/DefaultCatchBoundary'
import { NotFound } from '../components/NotFound'
import appCss from '../styles/app.css?url'
import { seo } from '../utils/seo'
import { getSupabaseServerClient } from '../utils/supabase'
import type * as Solid from 'solid-js'
const fetchUser = createServerFn({ method: 'GET' }).handler(async () => {
const supabase = getSupabaseServerClient()
const { data, error: _error } = await supabase.auth.getUser()
if (!data.user?.email) {
return null
}
return {
email: data.user.email,
}
})
export const Route = createRootRoute({
beforeLoad: async () => {
const user = await fetchUser()
return {
user,
}
},
head: () => ({
meta: [
{
charset: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
...seo({
title:
'TanStack Start | Type-Safe, Client-First, Full-Stack Solid Framework',
description: `TanStack Start is a type-safe, client-first, full-stack Solid framework. `,
}),
],
links: [
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
sizes: '180x180',
href: '/apple-touch-icon.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: { children: Solid.JSX.Element }) {
const { user } = Route.useRouteContext()()
return (
Home
{' '}
Posts
{user ? (
<>
{user.email}
Logout
>
) : (
Login
)}
{children}
)
}
```
--------------------------------
### Configure Content Collections
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Define a collection for markdown files, specify directory, include patterns, and define a Zod schema for front matter. Includes a transform function to extract front matter, body, and a header image.
```tsx
// content-collections.ts
import { defineCollection, defineConfig } from '@content-collections/core'
import matter from 'gray-matter'
function extractFrontMatter(content: string) {
const { data, content: body, excerpt } = matter(content, { excerpt: true })
return { data, body, excerpt: excerpt || '' }
}
const posts = defineCollection({
name: 'posts',
directory: './src/blog', // Directory containing your .md files
include: '*.md',
schema: (z) => ({
title: z.string(),
published: z.string().date(),
description: z.string().optional(),
authors: z.string().array(),
}),
transform: ({ content, ...post }) => {
const frontMatter = extractFrontMatter(content)
// Extract header image (first image in the document)
const headerImageMatch = content.match(/!\[([^\]]*)\]\(([^)]+)\)/)
const headerImage = headerImageMatch ? headerImageMatch[2] : undefined
return {
...post,
slug: post._meta.path,
excerpt: frontMatter.excerpt,
description: frontMatter.data.description,
headerImage,
content: frontMatter.body,
}
},
})
export default defineConfig({
collections: [posts],
})
```
--------------------------------
### Create React Markdown Component
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Implement a React component that takes markdown content, renders it using the `renderMarkdown` utility, and customizes HTML element rendering with `html-react-parser`.
```tsx
// src/components/Markdown.tsx
import parse, { type HTMLReactParserOptions, Element } from 'html-react-parser'
import { renderMarkdown, type MarkdownResult } from '~/utils/markdown'
type MarkdownProps = {
content: string
className?: string
}
export function Markdown({ content, className }: MarkdownProps) {
const [result, setResult] = useState(null)
useEffect(() => {
renderMarkdown(content).then(setResult)
}, [content])
if (!result) {
return
Loading...
}
const options: HTMLReactParserOptions = {
replace: (domNode) => {
if (domNode instanceof Element) {
// Customize rendering of specific elements
if (domNode.name === 'a') {
// Handle links
const href = domNode.attribs.href
if (href?.startsWith('/')) {
// Internal link - use your router's Link component
return (
{domToReact(domNode.children, options)}
)
}
}
if (domNode.name === 'img') {
// Add lazy loading to images
return (
)
}
}
}
}
return
{parse(result.markup, options)}
}
```
--------------------------------
### Track Route Loading Performance with TanStack Solid Router
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
Monitor both server-side (SSR) and client-side render times using loader hooks and Solid effects. Catches and logs errors with duration context.
```tsx
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/dashboard')({
loader: async ({ context }) => {
const startTime = Date.now()
try {
const data = await loadDashboardData()
const duration = Date.now() - startTime
// Log server-side performance
if (typeof window === 'undefined') {
console.log(`[SSR] Dashboard loaded in ${duration}ms`)
}
return data
} catch (error) {
const duration = Date.now() - startTime
console.error(`[LOADER] Dashboard error after ${duration}ms:`, error)
throw error
}
},
component: Dashboard,
})
function Dashboard() {
const data = Route.useLoaderData()
// Track client-side render time
Solid.createEffect(() => {
const renderTime = performance.now()
console.log(`[CLIENT] Dashboard rendered in ${renderTime}ms`)
})
return
Dashboard content
}
```
--------------------------------
### Enable Tree-Shaking with Static NODE_ENV
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Static replacement of process.env.NODE_ENV allows the bundler to eliminate development-only code blocks during production builds.
```typescript
if (process.env.NODE_ENV === 'development') {
// This code would NOT be eliminated without static replacement
enableDevTools()
logDebugInfo()
}
```
--------------------------------
### Header Merging Across Multiple Middlewares
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Demonstrates how headers are merged when multiple middlewares are applied, with later middlewares overriding earlier ones. Shows the final merged header result.
```typescript
import { createMiddleware } from '@tanstack/react-start'
const firstMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
return next({
headers: {
'X-Request-ID': '12345',
'X-Source': 'first-middleware',
},
})
},
)
const secondMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
return next({
headers: {
'X-Timestamp': Date.now().toString(),
'X-Source': 'second-middleware', // Overrides first middleware
},
})
},
)
// Final headers will include:
// - X-Request-ID: '12345' (from first)
// - X-Timestamp: '' (from second)
// - X-Source: 'second-middleware' (second overrides first)
```
--------------------------------
### ServerEntry Interface Definition
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-entry-point
The default export must conform to this interface for WinterCG-compatible runtimes like Cloudflare Workers.
```ts
export default {
fetch(req: Request, opts?: RequestOptions): Response | Promise {
// ...
},
}
```
--------------------------------
### Server Function with Locale and Timezone Formatting
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hydration-errors.md
Use getCookie to retrieve locale and timezone on the server, then format the current date using Intl.DateTimeFormat with those values. Pass the formatted string to the client to ensure hydration matches.
```tsx
// src/routes/index.tsx (example)
import { createFileRoute } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'
import { getCookie } from '@tanstack/solid-start/server'
export const getServerNow = createServerFn().handler(async () => {
const locale = getCookie('locale') || 'en-US'
const timeZone = getCookie('tz') || 'UTC'
return new Intl.DateTimeFormat(locale, {
dateStyle: 'medium',
timeStyle: 'short',
timeZone,
}).format(new Date())
})
export const Route = createFileRoute('/')({
loader: () => getServerNow(),
component: () => {
const serverNow = Route.useLoaderData() as string
return
},
})
```
--------------------------------
### Define Scope and Exclusions for Import Protection
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This snippet illustrates how to use `include`, `exclude`, and `ignoreImporters` to precisely control which files are checked by import protection and which importers are ignored.
```ts
importProtection: {
// Only check files matching these patterns
include: ['src/**'],
// Skip checking these files
exclude: ['src/generated/**'],
// Ignore violations when these files are the importer
ignoreImporters: ['**/*.test.ts', '**/*.spec.ts'],
}
```
--------------------------------
### Create Server Function to Add Jokes (TypeScript)
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/reading-writing-file
This server function uses `createServerFn` with a `POST` method to add new jokes to `jokes.json`. It includes input validation and writes the updated list of jokes back to the file.
```tsx
// src/serverActions/jokesActions.ts
import { createServerFn } from '@tanstack/react-start'
import * as fs from 'node:fs'
import { v4 as uuidv4 } from 'uuid' // Add this import
import type { Joke, JokesData } from '../types'
const JOKES_FILE = 'src/data/jokes.json'
export const getJokes = createServerFn({ method: 'GET' }).handler(async () => {
const jokes = await fs.promises.readFile(JOKES_FILE, 'utf-8')
return JSON.parse(jokes) as JokesData
})
// Add this new server function
export const addJoke = createServerFn({ method: 'POST' })
.inputValidator((data: { question: string; answer: string }) => {
// Validate input data
if (!data.question || !data.question.trim()) {
throw new Error('Joke question is required')
}
if (!data.answer || !data.answer.trim()) {
throw new Error('Joke answer is required')
}
return data
})
.handler(async ({ data }) => {
try {
// Read the existing jokes from the file
const jokesData = await getJokes()
// Create a new joke with a unique ID
const newJoke: Joke = {
id: uuidv4(),
question: data.question,
answer: data.answer,
}
// Add the new joke to the list
const updatedJokes = [...jokesData, newJoke]
// Write the updated jokes back to the file
await fs.promises.writeFile(
JOKES_FILE,
JSON.stringify(updatedJokes, null, 2),
'utf-8',
)
return newJoke
} catch (error) {
console.error('Failed to add joke:', error)
throw new Error('Failed to add joke')
}
})
```
--------------------------------
### Inspect Cache Headers with curl
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Use curl with the -I flag to check cache headers from your CDN. Look for Cache-Control directives, Age header, and X-Cache status to verify caching is working.
```bash
curl -I https://yoursite.com/blog/my-post
# Look for:
# Cache-Control: public, max-age=3600, stale-while-revalidate=86400
# Age: 1234 (time in cache)
# X-Cache: HIT (from CDN)
```
--------------------------------
### Defining a dynamic route with createFileRoute
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/routing.md
Export a Route variable using createFileRoute. The path argument is automatically managed by the TanStack Router plugin.
```tsx
// src/routes/posts/$postId.tsx
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/posts/$postId')({
component: PostComponent,
})
```
--------------------------------
### Import Protection Configuration
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This section details the "ImportProtectionOptions" interface, which allows fine-grained control over how import protection is applied within your project. It covers settings for enabling/disabling the feature, defining violation behavior, logging, and specifying include/exclude patterns for both client and server environments.
```APIDOC
## Configuration: ImportProtectionOptions
### Description
This configuration object defines the settings for the import protection plugin. It allows developers to control how imports are validated and handled across different environments (client/server) and specify rules for various file and specifier patterns.
### Options
- **enabled** (boolean) - Default: true - Set to false to disable the plugin
- **behavior** (string | object) - Default: { dev: 'mock', build: 'error' } - What to do on violation
- **log** ('once' | 'always') - Default: 'once' - Whether to deduplicate repeated violations
- **include** (Array) - Default: Start's srcDirectory - Only check importers matching these patterns
- **exclude** (Array) - Default: [] - Skip importers matching these patterns
- **ignoreImporters** (Array) - Default: [] - Ignore violations from these importers
- **maxTraceDepth** (number) - Default: 20 - Maximum depth for import traces
- **client** (object) - Default: See defaults above - Additional deny rules for the client environment
- **client.specifiers** (Array) - Default: Framework server specifiers - Specifier patterns denied in the client environment (additive with defaults)
- **client.files** (Array) - Default: ['**/*.server.*'] - File patterns denied in the client environment (replaces defaults)
- **client.excludeFiles** (Array) - Default: ['**/node_modules/**'] - Resolved files matching these patterns skip resolved-target checks (file-pattern + marker) (replaces defaults)
- **server** (object) - Default: See defaults above - Additional deny rules for the server environment
- **server.specifiers** (Array) - Default: [] - Specifier patterns denied in the server environment (replaces defaults; defaults for server.specifiers are [], so unlike client.specifiers this isn't additive)
- **server.files** (Array) - Default: ['**/*.client.*'] - File patterns denied in the server environment (replaces defaults)
```
--------------------------------
### Basic Server Component Caching with Route Path and Params
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Server components are cached by route path plus params. Navigating back to a previously visited route renders the cached component instantly.
```tsx
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => ({
Post: await getPost({ data: { postId: params.postId } }),
}),
component: PostPage,
})
```
--------------------------------
### Marking a file as client-only
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
Use this marker to explicitly restrict a module to the client environment, even if its filename doesn't follow the `.client.*` convention.
```typescript
// src/lib/local-storage.ts
import '@tanstack/react-start/client-only'
export function savePreferences(prefs: Record) {
localStorage.setItem('prefs', JSON.stringify(prefs))
}
```
--------------------------------
### Define environment-aware functions with createIsomorphicFn
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/environment-functions.md
Adapts behavior based on the runtime environment. Code within environment-specific handlers is automatically tree-shaken from the opposing bundle.
```tsx
import { createIsomorphicFn } from '@tanstack/solid-start'
const getEnv = createIsomorphicFn()
.server(() => 'server')
.client(() => 'client')
const env = getEnv()
// ℹ️ On the **server**, it returns `'server'`.
// ℹ️ On the **client**, it returns `'client'`.
```
```tsx
import { createIsomorphicFn } from '@tanstack/solid-start'
const serverImplementationOnly = createIsomorphicFn().server(() => 'server')
const server = serverImplementationOnly()
// ℹ️ On the **server**, it returns `'server'`.
// ℹ️ On the **client**, it is no-op (returns `undefined`)
```
```tsx
import { createIsomorphicFn } from '@tanstack/solid-start'
const clientImplementationOnly = createIsomorphicFn().client(() => 'client')
const client = clientImplementationOnly()
// ℹ️ On the **server**, it is no-op (returns `undefined`)
// ℹ️ On the **client**, it returns `'client'`.
```
```tsx
import { createIsomorphicFn } from '@tanstack/solid-start'
const noImplementation = createIsomorphicFn()
const noop = noImplementation()
// ℹ️ On both **client** and **server**, it is no-op (returns `undefined`)
```
--------------------------------
### Display Product Details with Clear Factual Statements
Source: https://tanstack.com/start/latest/docs/framework/react/guide/llmo
React component that renders product information in a semantic HTML structure with explicit, extractable facts. Uses proper article markup and clear prose to make product attributes easily understandable by AI systems and search engines.
```tsx
// Good: Clear, extractable facts
function ProductDetails({ product }) {
return (
{product.name}
{product.name} is a {product.category} made by {product.brand}. It costs
${product.price} and is available in {product.colors.join(', ')}.
)
}
```
--------------------------------
### Blog Post ISR Pattern
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Cache blog posts for 1 hour on CDN with 7-day stale-while-revalidate, and 5 minutes on client. Suitable for content that updates infrequently.
```typescript
export const Route = createFileRoute('/blog/$slug')({
loader: async ({ params }) => fetchPost(params.slug),
headers: () => ({
// Cache for 1 hour, allow stale for 7 days
'Cache-Control': 'public, max-age=3600, stale-while-revalidate=604800',
}),
staleTime: 5 * 60_000, // 5 minutes client-side
})
```
--------------------------------
### Root Component with Outlet
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-trellaux
Main root component that renders the RootDocument wrapper with an Outlet for child routes. This is the entry point for all nested route components.
```TypeScript
function RootComponent() {
return (
)
}
```
--------------------------------
### Import Tailwind CSS in CSS File (v4)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/tailwind-integration
Create a CSS file with the Tailwind import directive for version 4 configuration.
```css
/* src/styles/app.css */
@import 'tailwindcss' source('../');
```
--------------------------------
### Server Component Slots and Limitations
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Documents the limitations of slots in server components, including that slots are opaque on the server and React.Children utilities won't work. Provides guidance on using render props as an alternative approach.
```APIDOC
## Slots are Opaque on the Server
### Description
The server cannot inspect slot content. `React.Children.map()` and `cloneElement()` won't work on `props.children` because children are placeholders on the server.
### Limitation
- `React.Children.map()` - Not supported
- `React.cloneElement()` - Not supported
- Direct children inspection - Not supported
### Incorrect Approach
```tsx
// Won't work - children is a placeholder on the server
createCompositeComponent((props: { children?: React.ReactNode }) => (
)
```
```
--------------------------------
### Netlify Cache Configuration
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Use _headers file in public directory to configure cache policies per route. Netlify respects Cache-Control headers and supports stale-while-revalidate directives.
```plaintext
# public/_headers
/blog/*
Cache-Control: public, max-age=3600, stale-while-revalidate=86400
/api/*
Cache-Control: public, max-age=300
```
--------------------------------
### Implement Error Boundaries for Client and Server
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
Use Solid error boundaries on the client side and try-catch blocks in server functions to handle and log errors with context. Provides user-friendly fallback UI.
```tsx
// Client-side error boundary
import { ErrorBoundary } from 'solid-error-boundary'
function ErrorFallback({ error, resetErrorBoundary }: any) {
// Log client errors
console.error('[CLIENT ERROR]:', error)
// Could also send to external service
// sendErrorToService(error)
return (
Something went wrong
)
}
export function App() {
return (
)
}
// Server function error handling
const riskyOperation = createServerFn().handler(async () => {
try {
return await performOperation()
} catch (error) {
// Log server errors with context
console.error('[SERVER ERROR]:', {
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
// Add request context if available
})
// Return user-friendly error
throw new Error('Operation failed. Please try again.')
}
})
```
--------------------------------
### Configure SWR caching with staleTime and gcTime
Source: https://tanstack.com/start/latest/docs/framework/react/comparison
Set up automatic caching and revalidation for a route loader. staleTime controls how long data is considered fresh; gcTime controls how long cached data persists in memory.
```TypeScript
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => fetchPost(params.postId),
staleTime: 10_000, // Consider fresh for 10 seconds
gcTime: 5 * 60_000, // Keep in memory for 5 minutes
})
```
--------------------------------
### Access Request Headers and Set Response Headers
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-functions.md
Use getRequest, getRequestHeader, setResponseHeaders, and setResponseStatus utilities to access incoming request data and customize HTTP responses, such as setting cache control headers.
```tsx
import { createServerFn } from '@tanstack/solid-start'
import {
getRequest,
getRequestHeader,
setResponseHeaders,
setResponseStatus,
} from '@tanstack/solid-start/server'
export const getCachedData = createServerFn({ method: 'GET' }).handler(
async () => {
// Access the incoming request
const request = getRequest()
const authHeader = getRequestHeader('Authorization')
// Set response headers (e.g., for caching)
setResponseHeaders(
new Headers({
'Cache-Control': 'public, max-age=300',
'CDN-Cache-Control': 'max-age=3600, stale-while-revalidate=600',
}),
)
// Optionally set status code
setResponseStatus(200)
return fetchData()
},
)
```
--------------------------------
### Client Hydration with Error Boundary
Source: https://tanstack.com/start/latest/docs/framework/react/guide/client-entry-point.md
Wrap the StartClient component with a custom ErrorBoundary to catch and handle client-side errors gracefully.
```tsx
// src/client.tsx
import { StartClient } from '@tanstack/react-start/client'
import { StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'
import { ErrorBoundary } from './components/ErrorBoundary'
hydrateRoot(
document,
,
)
```
--------------------------------
### CSS Modules in Server Components
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
CSS Modules and global CSS imports work in server components. Styles are extracted and sent to the client.
```tsx
import styles from './Card.module.css'
const getCard = createServerFn().handler(async () => {
return renderServerComponent(
Server Rendered
,
)
})
```
--------------------------------
### Separate server-only logic from function wrappers
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Isolate database queries in .server.ts files and import them into .functions.ts wrappers to ensure clean boundaries.
```tsx
// users.server.ts - Server-only helpers
import { db } from '~/db'
export async function findUserById(id: string) {
return db.query.users.findFirst({ where: eq(users.id, id) })
}
```
```tsx
// users.functions.ts - Server functions
import { createServerFn } from '@tanstack/react-start'
import { findUserById } from './users.server'
export const getUser = createServerFn({ method: 'GET' })
.inputValidator((data: { id: string }) => data)
.handler(async ({ data }) => {
return findUserById(data.id)
})
```
--------------------------------
### Call server functions from components with useServerFn
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-functions.md
Use the useServerFn() hook in components to call server functions. Typically combined with useQuery for data fetching and caching.
```tsx
// In a component
function PostList() {
const getPosts = useServerFn(getServerPosts)
const { data } = useQuery({
queryKey: ['posts'],
queryFn: () => getPosts(),
})
}
```
--------------------------------
### Trace Server Functions with OpenTelemetry
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Instrument server functions with active spans to track execution, set attributes, and record exceptions. Use tracer.startActiveSpan to wrap async handlers with automatic error handling.
```typescript
// Server function tracing
import { trace, SpanStatusCode } from '@opentelemetry/api'
const tracer = trace.getTracer('tanstack-start')
const getUserWithTracing = createServerFn({ method: 'GET' })
.inputValidator((id: string) => id)
.handler(async ({ data: id }) => {
return tracer.startActiveSpan('get-user', async (span) => {
span.setAttributes({
'user.id': id,
operation: 'database.query',
})
try {
const user = await db.users.findUnique({ where: { id } })
span.setStatus({ code: SpanStatusCode.OK })
return user
} catch (error) {
span.recordException(error)
span.setStatus({
code: SpanStatusCode.ERROR,
message: error.message,
})
throw error
} finally {
span.end()
}
})
})
```
--------------------------------
### Apply route-level middleware to all handlers
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Define middleware at the server level to run it for every handler in the route. This is ideal for shared concerns like authentication.
```tsx
// routes/hello.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/hello')({
server: {
middleware: [authMiddleware, loggerMiddleware], // Applies to all handlers
handlers: {
GET: async ({ request }) => {
return new Response('Hello, World! from ' + request.url)
},
POST: async ({ request }) => {
const body = await request.json()
return new Response(`Hello, ${body.name}!`)
},
},
},
})
```
--------------------------------
### Disable Optional Asset Preloading Features
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Disable ETag generation and Gzip compression to reduce server overhead when these features are not required.
```bash
ASSET_PRELOAD_ENABLE_ETAG=false \
ASSET_PRELOAD_ENABLE_GZIP=false \
bun run server.ts
```
--------------------------------
### Configure asset prefix and cross-origin settings
Source: https://tanstack.com/start/latest/docs/framework/react/guide/cdn-asset-urls.md
Uses the object shorthand to set both a URL prefix and a global cross-origin attribute for link tags. This configuration is automatically cached.
```tsx
// src/server.ts
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/react-start/server'
import { createServerEntry } from '@tanstack/react-start/server-entry'
const handler = createStartHandler({
handler: defaultStreamHandler,
transformAssets: {
prefix: process.env.CDN_ORIGIN || '',
crossOrigin: 'anonymous',
},
})
export default createServerEntry({ fetch: handler })
```
--------------------------------
### createServerOnlyFn Wrapper for Server-Only Helpers
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/import-protection.md
Wraps a server-only helper in `createServerOnlyFn()` to keep it in the same file while ensuring it never runs on the client. The compiler removes the server-only import and replaces the function with an error-throwing stub on the client.
```typescript
import { createServerOnlyFn } from '@tanstack/solid-start'
import { getUsers } from './db/queries.server'
export const leakyHelper = createServerOnlyFn(() => {
return getUsers()
})
```
--------------------------------
### Reactive Loading Indicator Component Logic
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-trellaux
Uses useRouterState to select the isLoading property and apply conditional CSS classes for a smooth transition effect.
```tsx
const isLoading = useRouterState({ select: (s) => s.isLoading })
return (
)
}
```
--------------------------------
### Composable client and server middleware
Source: https://tanstack.com/start/latest/docs/framework/react/comparison
Define middleware that runs on both client and server with separate logic for each environment. Client middleware can add headers; server middleware can validate auth and attach context.
```TypeScript
const authMiddleware = createMiddleware({ type: 'function' })
.client(async ({ next }) => {
// Run auth checks on client
return next({
headers: { Authorization: `Bearer ${getToken()}` },
})
})
.server(async ({ next }) => {
// Validate auth on server
return next({ context: { user: await getUser() } })
})
```
--------------------------------
### Implement Logging in Server Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Track execution time and log errors within server function handlers to monitor database queries and performance.
```tsx
import { createServerFn } from '@tanstack/react-start'
const getUser = createServerFn({ method: 'GET' })
.inputValidator((id: string) => id)
.handler(async ({ data: id }) => {
const startTime = Date.now()
try {
console.log(`[SERVER] Fetching user ${id}`)
const user = await db.users.findUnique({ where: { id } })
if (!user) {
console.log(`[SERVER] User ${id} not found`)
throw new Error('User not found')
}
const duration = Date.now() - startTime
console.log(`[SERVER] User ${id} fetched in ${duration}ms`)
return user
} catch (error) {
const duration = Date.now() - startTime
console.error(
`[SERVER] Error fetching user ${id} after ${duration}ms:`,
error,
)
throw error
}
})
```
--------------------------------
### Add Custom Headers via Client Middleware
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Use createMiddleware to add Authorization headers to outgoing requests. Headers passed to next() are merged with headers from other middlewares and call sites.
```tsx
import { createMiddleware } from '@tanstack/solid-start'
import { getToken } from 'my-auth-library'
const authMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
return next({
headers: {
Authorization: `Bearer ${getToken()}`,
},
})
},
)
```
--------------------------------
### Throw Not-Found Errors for Missing Resources
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-functions.md
Use the notFound function from @tanstack/solid-router to handle cases where a requested resource does not exist. This is typically used after querying a database.
```tsx
import { createServerFn } from '@tanstack/solid-start'
import { notFound } from '@tanstack/solid-router'
export const getPost = createServerFn()
.inputValidator((data: { id: string }) => data)
.handler(async ({ data }) => {
const post = await db.findPost(data.id)
if (!post) {
throw notFound()
}
return post
})
```
--------------------------------
### Call server functions from loaders and components
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Integrate server functions directly into route loaders or use the useServerFn hook within components.
```tsx
// In a route loader
export const Route = createFileRoute('/posts')({
loader: () => getServerPosts(),
})
// In a component
function PostList() {
const getPosts = useServerFn(getServerPosts)
const { data } = useQuery({
queryKey: ['posts'],
queryFn: () => getPosts(),
})
}
```
--------------------------------
### Client-Side Context: Accessing VITE_ Prefixed Variables
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Client code can only access environment variables that are prefixed with VITE_ using import.meta.env. Other variables will be undefined for security.
```typescript
// Client configuration
export function ApiProvider({ children }: { children: React.ReactNode }) {
const apiUrl = import.meta.env.VITE_API_URL // ✅ Public
const apiKey = import.meta.env.VITE_PUBLIC_KEY // ✅ Public
// This would be undefined (security feature):
// const secret = import.meta.env.DATABASE_URL // ❌ Undefined
return (
{children}
)
}
// Feature flags
export function FeatureGatedComponent() {
const enableNewFeature = import.meta.env.VITE_ENABLE_NEW_FEATURE === 'true'
if (!enableNewFeature) return null
return
}
```
--------------------------------
### Implement Redirects in Server Functions
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-functions.md
Use the redirect function from @tanstack/solid-router to redirect users during server function execution, commonly for authentication checks. Redirects are handled automatically when called from route lifecycles or components.
```tsx
import { createServerFn } from '@tanstack/solid-start'
import { redirect } from '@tanstack/solid-router'
export const requireAuth = createServerFn().handler(async () => {
const user = await getCurrentUser()
if (!user) {
throw redirect({ to: '/login' })
}
return user
})
```
--------------------------------
### Update package.json with Vite scripts
Source: https://tanstack.com/start/latest/docs/framework/react/build-from-scratch
Configure package.json to use Vite's CLI and set module type to ESM. Include dev and build scripts.
```json
{
// ...
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build"
}
}
```
--------------------------------
### Re-enable File Pattern Checking for Node Modules on Server
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
This configuration snippet shows how to override the default `excludeFiles` behavior to re-enable file-pattern checking for `node_modules` in the server environment.
```ts
importProtection: {
server: {
// Re-enable file-pattern checking for node_modules in the server environment
excludeFiles: [],
},
}
```
--------------------------------
### Detect SPA shell rendering with isShell
Source: https://tanstack.com/start/latest/docs/framework/react/guide/spa-mode
Use the isShell method from the router instance to identify if the current execution context is the prerendering shell phase.
```tsx
// src/routes/root.tsx
export default function Root() {
const isShell = useRouter().isShell()
if (isShell) console.log('Rendering the shell!')
}
```
--------------------------------
### Create a React Component to Display Data
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/reading-writing-file
A presentation component that maps over an array of joke objects. It includes conditional rendering for empty states and Tailwind CSS for styling.
```tsx
// src/components/JokesList.tsx
import { Joke } from '../types'
interface JokesListProps {
jokes: Joke[]
}
export function JokesList({ jokes }: JokesListProps) {
if (!jokes || jokes.length === 0) {
return
No jokes found. Add some!
}
return (
Jokes Collection
{jokes.map((joke) => (
{joke.question}
{joke.answer}
))}
)
}
```
--------------------------------
### Root Component with Clerk Provider
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-clerk-basic
Main root component that wraps the application with ClerkProvider for authentication and renders the RootDocument layout with an Outlet for nested routes.
```TypeScript
function RootComponent() {
return (
)
}
```
--------------------------------
### Define a basic server function
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-functions.md
Create a server-only function that can be invoked from components, loaders, or hooks.
```tsx
import { createServerFn } from '@tanstack/react-start'
export const getServerTime = createServerFn().handler(async () => {
// This runs only on the server
return new Date().toISOString()
})
// Call from anywhere - components, loaders, hooks, etc.
const time = await getServerTime()
```
--------------------------------
### Secure Environment Variables with Server-Only Functions
Source: https://tanstack.com/start/latest/docs/framework/react/guide/code-execution-patterns.md
Prevent sensitive keys from leaking into the client bundle by wrapping access in server-only boundaries.
```tsx
// ❌ Exposes to client bundle
const apiKey = process.env.SECRET_KEY
```
```tsx
// ✅ Server-only access
const apiKey = createServerOnlyFn(() => process.env.SECRET_KEY)
```
--------------------------------
### Bundle components using createCompositeComponent
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Use this method when bundled components need to accept slots or children independently. Each component in the bundle receives its own slot props.
```tsx
const getPageLayout = createServerFn().handler(async () => {
const user = await db.users.getCurrent()
const config = await db.config.get()
const [Header, Content, Footer] = await Promise.all([
createCompositeComponent((props: { children?: React.ReactNode }) => (
{props.children}
)),
createCompositeComponent(
(props: { renderActions?: () => React.ReactNode }) => (
Welcome, {user.name}
{props.renderActions?.()}
),
),
createCompositeComponent(() => (
)),
])
return { Header, Content, Footer }
})
export const Route = createFileRoute('/dashboard')({
loader: async () => ({
Layout: await getPageLayout(),
}),
component: DashboardPage,
})
```
--------------------------------
### Apply middleware to specific server route methods
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Use `createHandlers` utility to apply middleware to individual HTTP methods by passing a middleware array to the method object's `middleware` property.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware().server(() => {
//...
})
export const Route = createFileRoute('/foo')({
server: {
handlers: ({ createHandlers }) =>
createHandlers({
GET: {
middleware: [loggingMiddleware],
handler: () => {
//...
},
},
}),
},
})
```
--------------------------------
### Marking a file as server-only
Source: https://tanstack.com/start/latest/docs/framework/react/guide/import-protection.md
Use this marker to explicitly restrict a module to the server environment, even if its filename doesn't follow the `.server.*` convention.
```typescript
// src/lib/secrets.ts
import '@tanstack/react-start/server-only'
export const API_KEY = process.env.API_KEY
```
--------------------------------
### Create Static Authentication Middleware
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
Defines a base middleware to validate sessions and inject them into the request context for downstream use.
```tsx
// middleware.ts
import { createMiddleware } from '@tanstack/solid-start'
import { auth } from './my-auth'
export const authMiddleware = createMiddleware().server(
async ({ next, request }) => {
const session = await auth.getSession({ headers: request.headers })
if (!session) {
throw new Error('Unauthorized')
}
return await next({
context: { session },
})
},
)
```
--------------------------------
### CONFIG enabled
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/import-protection.md
A configuration property used to enable or disable the import protection feature entirely. This is useful for debugging or specific environment configurations.
```APIDOC
## CONFIG enabled
### Description
Toggle the import protection feature on or off.
### Method
CONFIG
### Endpoint
importProtection.enabled
### Parameters
#### Configuration
- **enabled** (boolean) - Required - Set to false to disable import protection entirely.
### Request Example
{
"importProtection": {
"enabled": false
}
}
### Response
#### Success Response (200)
- **status** (void) - Feature is disabled.
```
--------------------------------
### TanStack Router Root Configuration and Layout Components
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-static
This snippet defines the root route configuration for a TanStack Router application, including error and not-found components, and the main `RootComponent` and `RootLayout` for global UI structure and navigation.
```typescript
type: 'image/png',
sizes: '32x32',
href: '/favicon-32x32.png',
},
{
rel: 'icon',
type: 'image/png',
sizes: '16x16',
href: '/favicon-16x16.png',
},
{ rel: 'manifest', href: '/site.webmanifest', color: '#fffff' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
errorComponent: (props) => {
return (
)
},
notFoundComponent: () => ,
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootLayout({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### E-commerce Product Page ISR Pattern
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Use shorter cache times (5 minutes) due to frequent inventory changes, with 1-hour stale-while-revalidate. Client-side cache is 30 seconds to reflect price/stock updates quickly.
```typescript
export const Route = createFileRoute('/products/$id')({
loader: async ({ params }) => fetchProduct(params.id),
headers: () => ({
// Shorter cache due to inventory changes
'Cache-Control': 'public, max-age=300, stale-while-revalidate=3600',
}),
staleTime: 30_000, // 30 seconds client-side
})
```
--------------------------------
### Avoiding Client-Side Environment Variable Exposure
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
Directly accessing process.env exposes variables to the client bundle. Use createServerOnlyFn to ensure environment variables are accessed only on the server.
```tsx
// ❌ Exposes to client bundle
const apiKey = process.env.SECRET_KEY
// ✅ Server-only access
const apiKey = createServerOnlyFn(() => process.env.SECRET_KEY)
```
--------------------------------
### Combine route-level and handler-specific middleware
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-routes.md
Layer middleware by defining it at both the route and handler levels. Route-level middleware executes first, followed by method-specific middleware.
```tsx
// routes/hello.ts
import { createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/hello')({
server: {
middleware: [authMiddleware], // Runs first for all handlers
handlers: ({ createHandlers }) =>
createHandlers({
GET: async ({ request }) => {
return new Response('Hello, World!')
},
POST: {
middleware: [validationMiddleware], // Runs after authMiddleware, only for POST
handler: async ({ request }) => {
const body = await request.json()
return new Response(`Hello, ${body.name}!`)
},
},
}),
},
})
```
--------------------------------
### Configure Nitro Preset for Bun in vite.config.ts
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hosting.md
Set the Nitro preset to `'bun'` in your `vite.config.ts` file when deploying to Bun, especially if you invoke the build differently.
```ts
// vite.config.ts
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { defineConfig } from 'vite'
import { nitro } from 'nitro/vite'
import viteReact from '@vitejs/plugin-react'
export default defineConfig({
plugins: [tanstackStart(), nitro({ preset: 'bun' }), viteReact()],
})
```
--------------------------------
### Create Root Route with __root.tsx
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/routing.md
Define the root route using createRootRoute with head metadata and a RootComponent that renders HeadContent, Outlet, and Scripts. The root route is always matched and rendered, making it ideal for the application shell and global logic.
```typescript
// src/routes/__root.tsx
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from '@tanstack/solid-router'
import type { solidNode } from 'solid'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Starter',
},
],
}),
component: RootComponent,
})
function RootComponent() {
return (
)
}
function RootDocument({ children }: Readonly<{ children: Solid.JSX.Element }>) {
return (
<>
{children}
>
)
}
```
--------------------------------
### Fetch GitHub Directory Contents via Server Function
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Retrieve and filter file lists from the GitHub API to build dynamic navigation structures.
```tsx
// src/utils/docs.server.ts
type GitHubContent = {
name: string
path: string
type: 'file' | 'dir'
}
export const fetchRepoContents = createServerFn({ method: 'GET' })
.inputValidator(
(params: { repo: string; branch: string; path: string }) => params,
)
.handler(async ({ data: { repo, branch, path } }) => {
const url = `https://api.github.com/repos/${repo}/contents/${path}?ref=${branch}`
const response = await fetch(url, {
headers: {
Accept: 'application/vnd.github.v3+json',
// Authorization: `token ${process.env.GITHUB_TOKEN}`,
},
})
if (!response.ok) {
throw new Error(`Failed to fetch contents: ${response.status}`)
}
const contents: Array = await response.json()
return contents
.filter((item) => item.type === 'file' && item.name.endsWith('.md'))
.map((item) => ({
name: item.name.replace('.md', ''),
path: item.path,
}))
})
```
--------------------------------
### Hybrid SSR with ssr: 'data-only'
Source: https://tanstack.com/start/latest/docs/framework/react/guide/selective-ssr.md
Executes `beforeLoad` and `loader` on the server but renders the component on the client. Useful when data loading requires server-side logic but rendering depends on browser APIs.
```typescript
// src/routes/posts/$postId.tsx
export const Route = createFileRoute('/posts/$postId')({
ssr: 'data-only',
beforeLoad: () => {
console.log('Executes on the server during the initial request')
console.log('Executes on the client for subsequent navigation')
},
loader: () => {
console.log('Executes on the server during the initial request')
console.log('Executes on the client for subsequent navigation')
},
component: () =>
This component is rendered on the client
,
})
```
--------------------------------
### Stream Server Components with Async Generators
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Use async generators to yield composite components incrementally. This is ideal for large result sets where items should render as they become available.
```tsx
import {
CompositeComponent,
createCompositeComponent,
} from '@tanstack/react-start/rsc'
const streamNotifications = createServerFn().handler(async function* () {
// Yield initial batch immediately
const recent = await db.notifications.getRecent(3)
for (const notification of recent) {
yield await createCompositeComponent<{
renderActions?: (data: { id: string }) => React.ReactNode
}>((props) => (
{notification.title}
{notification.message}
{props.renderActions?.({ id: notification.id })}
))
}
// Stream older notifications with delays
const older = await db.notifications.getOlder(5)
for (const notification of older) {
await new Promise((resolve) => setTimeout(resolve, 300))
yield await createCompositeComponent<{
renderActions?: (data: { id: string }) => React.ReactNode
}>((props) => (
)
}
```
--------------------------------
### Create Authorization Middleware Factory
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/middleware.md
A middleware factory that accepts dynamic permissions and composes with the base authentication middleware.
```tsx
// middleware.ts
import { createMiddleware } from '@tanstack/solid-start'
import { auth } from './my-auth'
export const authMiddleware = createMiddleware().server(
async ({ next, request }) => {
// ... (implementation from authentication example above)
},
)
type Permissions = Record
export function authorizationMiddleware(permissions: Permissions) {
return createMiddleware({ type: 'function' })
.middleware([authMiddleware])
.server(async ({ next, context }) => {
const granted = await auth.hasPermission(context.session, permissions)
if (!granted) {
throw new Error('Forbidden')
}
return await next()
})
}
```
--------------------------------
### Client-Only Function with createClientOnlyFn
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-functions.md
Creates a function that can only be executed on the client. Calling it on the server will throw an error.
```tsx
import { createClientOnlyFn } from '@tanstack/react-start'
const foo = createClientOnlyFn(() => 'bar')
foo() // ✅ On client: returns "bar"
// ❌ On server: throws "createClientOnlyFn() functions can only be called on the client!"
```
--------------------------------
### Flight Stream API Route with renderToReadableStream
Source: https://tanstack.com/start/latest/docs/framework/react/guide/server-components.md
Create an API route that renders React elements to a Flight stream. Use renderToReadableStream from @tanstack/react-start/rsc to generate the stream response.
```tsx
// src/routes/api/rsc.ts - API route with Flight stream
import { createAPIFileRoute } from '@tanstack/react-start/api'
import { createServerFn } from '@tanstack/react-start'
import { renderToReadableStream } from '@tanstack/react-start/rsc'
const getFlightStream = createServerFn({ method: 'GET' }).handler(async () => {
return renderToReadableStream(
Server Rendered Content
)
})
export const APIRoute = createAPIFileRoute('/api/rsc')({
GET: async () => {
const stream = await getFlightStream()
return new Response(stream, {
headers: { 'Content-Type': 'text/x-component' },
})
},
})
```
--------------------------------
### Replace Next.js Image with Unpic
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Use Unpic's Image component as a drop-in replacement for next/image. Update import and change width/height from strings to numbers.
```tsx
import Image from 'next/image' // [!code --]
import { Image } from '@unpic/react' // [!code ++]
function Component() {
return (
)
}
```
--------------------------------
### Marketing Landing Page ISR Pattern
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Cache landing pages for 24 hours with 7-day stale-while-revalidate for stable campaign content. Client-side cache is 1 hour.
```typescript
export const Route = createFileRoute('/landing/$campaign')({
loader: async ({ params }) => fetchCampaign(params.campaign),
headers: () => ({
// Long cache for stable content
'Cache-Control': 'public, max-age=86400, stale-while-revalidate=604800',
}),
staleTime: 60 * 60_000, // 1 hour client-side
})
```
--------------------------------
### Multi-Tier Caching with ISR and Client-Side Cache
Source: https://tanstack.com/start/latest/docs/framework/react/guide/isr
Combine CDN caching via headers with TanStack Router's client-side caching using staleTime and gcTime. Creates a three-tier strategy: CDN edge, client fresh data, and client memory.
```typescript
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
return fetchPost(params.postId)
},
// CDN caching (via headers)
headers: () => ({
'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400',
}),
// Client-side caching (via TanStack Router)
staleTime: 60_000, // Consider data fresh for 60 seconds on client
gcTime: 5 * 60_000, // Keep in memory for 5 minutes
})
```
--------------------------------
### Configure Custom Shell Mask Path
Source: https://tanstack.com/start/latest/docs/framework/react/guide/spa-mode
Set a custom shell mask path in the Vite config; the default value of '/' is recommended and should only be changed if necessary.
```typescript
// vite.config.ts
export default defineConfig({
plugins: [
tanstackStart({
spa: {
maskPath: '/app',
},
}),
],
})
```
--------------------------------
### Create Authorization Middleware Factory
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Parameterized middleware factory that validates access based on dynamic permissions. Composes with authMiddleware to access context.session from upstream middleware.
```typescript
// middleware.ts
import { createMiddleware } from '@tanstack/react-start'
import { auth } from './my-auth'
export const authMiddleware = createMiddleware().server(
async ({ next, request }) => {
// ... (implementation from authentication example above)
},
)
type Permissions = Record
export function authorizationMiddleware(permissions: Permissions) {
return createMiddleware({ type: 'function' })
.middleware([authMiddleware])
.server(async ({ next, context }) => {
const granted = await auth.hasPermission(context.session, permissions)
if (!granted) {
throw new Error('Forbidden')
}
return await next()
})
}
```
--------------------------------
### Environment-Specific Client Hydration
Source: https://tanstack.com/start/latest/docs/framework/react/guide/client-entry-point.md
Implement conditional logic to toggle StrictMode or display debug indicators based on the development or production environment.
```tsx
// src/client.tsx
import { StartClient } from '@tanstack/react-start/client'
import { StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'
const App = (
<>
{import.meta.env.DEV &&
Development Mode
}
>
)
hydrateRoot(
document,
import.meta.env.DEV ? {App} : App,
)
```
--------------------------------
### Configure wrangler.json
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Define the Cloudflare Workers configuration, including compatibility dates and the server entry point.
```json
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "tanstack-start-app",
"compatibility_date": "2025-09-02",
"compatibility_flags": ["nodejs_compat"],
"main": "@tanstack/solid-start/server-entry",
"vars": {
"MY_VAR": "Hello from Cloudflare"
}
}
```
--------------------------------
### Render a Single Post from Content Collection
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Load a single post by slug using `@tanstack/react-router`'s `loader` function and render its content, including front matter details and markdown body.
```tsx
// src/routes/blog.$slug.tsx
import { createFileRoute, notFound } from '@tanstack/react-router'
import { allPosts } from 'content-collections'
import { Markdown } from '~/components/Markdown'
export const Route = createFileRoute('/blog/$slug')({
loader: ({ params }) => {
const post = allPosts.find((p) => p.slug === params.slug)
if (!post) {
throw notFound()
}
return post
},
component: BlogPost,
})
function BlogPost() {
const post = Route.useLoaderData()
return (
{post.title}
By {post.authors.join(', ')} on {post.published}
)
}
```
--------------------------------
### server.excludeFiles
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/import-protection.md
Configures patterns for files that should be excluded from resolved-target checks, replacing the default exclusion list.
```APIDOC
## server.excludeFiles
### Description
Resolved files matching these patterns skip resolved-target checks (file-pattern + marker). This replaces the default exclusion patterns.
### Parameters
#### Configuration Property
- **server.excludeFiles** (Pattern[]) - Optional - Array of patterns to exclude. Default: `['**/node_modules/**']`.
```
--------------------------------
### Configure Template Paths in Tailwind v3
Source: https://tanstack.com/start/latest/docs/framework/react/guide/tailwind-integration
Add content paths to tailwind.config.js to scan template files for Tailwind class usage.
```javascript
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {},
},
plugins: [],
}
```
--------------------------------
### Create Static Authentication Middleware
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Validates the session from request headers and injects it into context for downstream middlewares. Throws an error if no session is found.
```typescript
// middleware.ts
import { createMiddleware } from '@tanstack/react-start'
import { auth } from './my-auth'
export const authMiddleware = createMiddleware().server(
async ({ next, request }) => {
const session = await auth.getSession({ headers: request.headers })
if (!session) {
throw new Error('Unauthorized')
}
return await next({
context: { session },
})
},
)
```
--------------------------------
### Build Movie Display Components in React
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/fetching-external-api
These components (`MovieCard`, `MovieDetails`) are used to render individual movie data, displaying details like title, overview, release date, and rating.
```tsx
// MovieCard component
const MovieCard = ({ movie }: { movie: Movie }) => {
return (
{movie.poster_path && (
)}
)
}
// MovieDetails component
const MovieDetails = ({ movie }: { movie: Movie }) => {
return (
<>
>
)
}
```
--------------------------------
### Display All Posts from Content Collection
Source: https://tanstack.com/start/latest/docs/framework/react/guide/rendering-markdown.md
Access `allPosts` from `content-collections` to list blog posts, sort them by published date, and link to individual post pages using `@tanstack/react-router`.
```tsx
// src/routes/blog.index.tsx
import { createFileRoute } from '@tanstack/react-router'
import { allPosts } from 'content-collections'
export const Route = createFileRoute('/blog/')({
component: BlogIndex,
})
function BlogIndex() {
// Posts are sorted by published date
const sortedPosts = allPosts.sort(
(a, b) => new Date(b.published).getTime() - new Date(a.published).getTime(),
)
return (
Blog
{sortedPosts.map((post) => (
{post.title}
{post.excerpt}
{post.published}
))}
)
}
```
--------------------------------
### Define a JokesList component using Solid.js and Tailwind CSS
Source: https://tanstack.com/start/latest/docs/framework/solid/tutorial/reading-writing-file.md
This component renders a list of jokes with conditional empty states. It uses Tailwind CSS classes for styling and layout.
```tsx
// src/components/JokesList.tsx
import { Joke } from '../types'
interface JokesListProps {
jokes: Joke[]
}
export function JokesList({ jokes }: JokesListProps) {
if (!jokes || jokes.length === 0) {
return
No jokes found. Add some!
}
return (
Jokes Collection
{jokes.map((joke) => (
{joke.question}
{joke.answer}
))}
)
}
```
--------------------------------
### Root Document Shell Component
Source: https://tanstack.com/start/latest/docs/framework/react/examples/start-basic-cloudflare
The primary HTML shell component that renders the head content, global navigation, and application children.
```tsx
function RootDocument({ children }: { children: React.ReactNode }) {
return (
Home
{' '}
Posts
{' '}
Users
{' '}
Pathless Layout
{' '}
Deferred
{' '}
This Route Does Not Exist
{children}
)
}
```
--------------------------------
### Creating Environment-Specific Implementations in TSX
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/execution-model.md
Use createIsomorphicFn to define separate logic for server and client environments within a single function. This allows for safe access to environment-specific globals like process or navigator.
```tsx
import { createIsomorphicFn } from '@tanstack/solid-start'
// Different implementation per environment
const getDeviceInfo = createIsomorphicFn()
.server(() => ({ type: 'server', platform: process.platform }))
.client(() => ({ type: 'client', userAgent: navigator.userAgent }))
```
--------------------------------
### Wrap Unstable UI in ClientOnly
Source: https://tanstack.com/start/latest/docs/framework/react/guide/hydration-errors.md
Use the `` component to prevent server-side rendering of UI elements that are inherently unstable or dynamic, thus avoiding hydration errors.
```tsx
import { ClientOnly } from '@tanstack/react-router'
;—}>
```
--------------------------------
### Custom Function ID Generation in Vite Config
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/server-functions.md
Configure the tanstackStart Vite plugin with a custom generateFunctionId function that receives filename and functionName parameters. Return a custom ID string or undefined to use the default SHA256 hash. Use deterministic inputs to maintain stable IDs between builds.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
export default defineConfig({
plugins: [
tanstackStart({
serverFns: {
generateFunctionId: ({ filename, functionName }) => {
// Return a custom ID string
return crypto
.createHash('sha1')
.update(`${filename}--${functionName}`)
.digest('hex')
// If you return undefined, the default is used
// return undefined
},
},
}),
react(),
],
})
```
--------------------------------
### Simple Error Reporting and Monitoring Route
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
Implement a basic in-memory error store and a server-side route to expose reported errors for administrative review.
```tsx
// utils/error-reporter.ts
const errorStore = new Map<
string,
{ count: number; lastSeen: Date; error: any }
>()
export function reportError(error: Error, context?: any) {
const key = `${error.name}:${error.message}`
const existing = errorStore.get(key)
if (existing) {
existing.count++
existing.lastSeen = new Date()
} else {
errorStore.set(key, {
count: 1,
lastSeen: new Date(),
error: {
name: error.name,
message: error.message,
stack: error.stack,
context,
},
})
}
// Log immediately
console.error('[ERROR REPORTED]:', {
error: error.message,
count: existing ? existing.count : 1,
context,
})
}
// Error reporting endpoint
// routes/errors.ts
export const Route = createFileRoute('/admin/errors')({
server: {
handlers: {
GET: async () => {
const errors = Array.from(errorStore.entries()).map(([key, data]) => ({
id: key,
...data,
}))
return Response.json({ errors })
},
},
},
})
```
--------------------------------
### Implement Next.js Server Actions
Source: https://tanstack.com/start/latest/docs/framework/react/start-vs-nextjs
Define server-side logic using the 'use server' directive, typically used with FormData in Next.js applications.
```tsx
'use server'
export async function createPost(formData: FormData) {
const title = formData.get('title')
// No compile-time type safety on inputs
return db.posts.create({ title })
}
```
--------------------------------
### Database integration using server functions
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/databases.md
Call your database client or driver within a server function handler to perform read and write operations.
```tsx
import { createServerFn } from '@tanstack/solid-start'
const db = createMyDatabaseClient()
export const getUser = createServerFn().handler(async ({ context }) => {
const user = await db.getUser(context.userId)
return user
})
export const createUser = createServerFn({ method: 'POST' }).handler(
async ({ data }) => {
const user = await db.createUser(data)
return user
},
)
```
--------------------------------
### Create Automatic Tracing Middleware
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/observability.md
Use middleware to automatically trace HTTP requests with method, URL, and route information. Captures response status and errors for all requests.
```typescript
// Middleware for automatic tracing
import { createMiddleware } from '@tanstack/solid-start'
import { trace, SpanStatusCode } from '@opentelemetry/api'
const tracer = trace.getTracer('tanstack-start')
const tracingMiddleware = createMiddleware().handler(
async ({ next, request }) => {
const url = new URL(request.url)
return tracer.startActiveSpan(
`${request.method} ${url.pathname}`,
async (span) => {
span.setAttributes({
'http.method': request.method,
'http.url': request.url,
'http.route': url.pathname,
})
try {
const response = await next()
span.setAttribute('http.status_code', response.status)
span.setStatus({ code: SpanStatusCode.OK })
return response
} catch (error) {
span.recordException(error)
span.setStatus({
code: SpanStatusCode.ERROR,
message: error.message,
})
throw error
} finally {
span.end()
}
},
)
},
)
```
--------------------------------
### onViolation
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/import-protection.md
Defines a callback function that is triggered whenever a violation is detected by the server.
```APIDOC
## onViolation
### Description
Callback invoked on every violation.
### Parameters
#### Configuration Property
- **onViolation** (function) - Optional - Callback function invoked on every violation. Default: `undefined`.
```
--------------------------------
### Update Link Component from Next.js to TanStack Router
Source: https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js
Replace Next.js Link import and href prop with TanStack Router Link component using the to prop for navigation.
```tsx
- import Link from "next/link" // [!code --]
+ import { Link } from "@tanstack/react-router" // [!code ++]
function Component() {
- return Dashboard // [!code --]
+ return Dashboard // [!code ++]
}
```
--------------------------------
### Create server function middleware with client and server methods
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Set `type: 'function'` to create server function middleware that supports both client-side and server-side logic. Method order is enforced by TypeScript for type safety.
```tsx
import { createMiddleware } from '@tanstack/react-start'
const loggingMiddleware = createMiddleware({ type: 'function' })
.client(() => {
//...
})
.server(() => {
//...
})
```
--------------------------------
### Prevent hydration mismatches with consistent rendering
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/code-execution-patterns.md
Avoid rendering different content on server vs client (e.g., current time). Use createSignal and createEffect to defer client-only rendering until after hydration completes.
```tsx
// ❌ Different content server vs client
function CurrentTime() {
return
}
```
--------------------------------
### Data Flow Sequence Diagram
Source: https://tanstack.com/start/latest/docs/framework/react/tutorial/reading-writing-file
This sequence diagram illustrates the data flow within the DevJokes application, showing interactions between the user, UI, route loader, server, and data store for both visiting the home page and adding a new joke.
```mermaid
sequenceDiagram
autonumber
actor User
participant UI as Browser (HomePage + Form)
participant Loader as Route Loader (loader)
participant Server
participant Store as jokes.json
%% Visiting the Home Page
User ->> UI: Visit /
UI ->> Loader: loader() calls getJokes()
Loader ->> Server: getJokes()
Server ->> Store: Read jokes.json
Store -->> Server: jokes data
Server -->> Loader: jokes[]
Loader -->> UI: useLoaderData() → jokes[]
%% Adding a New Joke
User ->> UI: Fill form and submit
UI ->> Server: handleSubmit → addJoke(newJoke)
Server ->> Store: Read jokes.json
Server ->> Store: Write updated jokes.json
Server -->> UI: addJoke() resolved
UI ->> Loader: router.invalidate() (re-run loader)
Loader ->> Server: getJokes()
Server ->> Store: Read jokes.json
Store -->> Server: updated jokes[]
Server -->> Loader: updated jokes[]
Loader -->> UI: useLoaderData() → updated jokes[]
```
--------------------------------
### Correctly Handling Loaders for Server-Only Operations
Source: https://tanstack.com/start/latest/docs/framework/react/guide/execution-model.md
Route loaders run on both server and client, so process.env access within them will expose secrets. Use createServerFn for secure, server-only data fetching within loaders.
```tsx
// ❌ Assuming loader is server-only
export const Route = createFileRoute('/users')({
loader: () => {
// This runs on BOTH server and client!
const secret = process.env.SECRET // Exposed to client
return fetch(`/api/users?key=${secret}`)
},
})
// ✅ Use server function for server-only operations
const getUsersSecurely = createServerFn().handler(() => {
const secret = process.env.SECRET // Server-only
return fetch(`/api/users?key=${secret}`)
})
export const Route = createFileRoute('/users')({
loader: () => getUsersSecurely(), // Isomorphic call to server function
})
```
--------------------------------
### Set Custom Headers in Client Middleware
Source: https://tanstack.com/start/latest/docs/framework/react/guide/middleware.md
Add headers to outgoing requests using createMiddleware with a headers object passed to next(). Useful for authentication tokens and request identification.
```typescript
import { createMiddleware } from '@tanstack/react-start'
import { getToken } from 'my-auth-library'
const authMiddleware = createMiddleware({ type: 'function' }).client(
async ({ next }) => {
return next({
headers: {
Authorization: `Bearer ${getToken()}`,
},
})
},
)
```
--------------------------------
### Inject dynamic data into the SPA shell
Source: https://tanstack.com/start/latest/docs/framework/react/guide/spa-mode
Define a loader on the root route to fetch and include dynamic data during the shell's SSR prerendering process.
```tsx
// src/routes/__root.tsx
export const RootRoute = createRootRoute({
loader: async () => {
return {
name: 'Tanner',
}
},
component: Root,
})
export default function Root() {
const { name } = useLoaderData()
return (
Hello, {name}!
)
}
```
--------------------------------
### Configure vite.config.ts for Cloudflare
Source: https://tanstack.com/start/latest/docs/framework/solid/guide/hosting.md
Register the cloudflare plugin within the Vite configuration, ensuring the SSR environment is correctly named.
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/solid-start/plugin/vite'
import { cloudflare } from '@cloudflare/vite-plugin'
import viteSolid from 'vite-plugin-solid'
export default defineConfig({
plugins: [
cloudflare({ viteEnvironment: { name: 'ssr' } }),
tanstackStart(),
viteSolid({ ssr: true }),
],
})
```
--------------------------------
### Configure default SSR behavior in createStart
Source: https://tanstack.com/start/latest/docs/framework/react/guide/selective-ssr.md
Set `defaultSsr: false` to disable SSR for all routes unless explicitly enabled. This overrides the default `ssr: true` behavior.
```typescript
// src/start.ts
import { createStart } from '@tanstack/react-start'
export const startInstance = createStart(() => ({
// Disable SSR by default
defaultSsr: false,
}))
```
--------------------------------
### Server-Side Context: Accessing All Environment Variables
Source: https://tanstack.com/start/latest/docs/framework/react/guide/environment-variables.md
Server functions can securely access any environment variable using process.env, including sensitive data like database connection strings and API keys, which are never exposed to the client.
```typescript
import { createServerFn } from '@tanstack/react-start'
// Database connection (server-only)
const connectToDatabase = createServerFn().handler(async () => {
const connectionString = process.env.DATABASE_URL // No prefix needed
const apiKey = process.env.EXTERNAL_API_SECRET // Stays on server
// These variables are never exposed to the client
return await database.connect(connectionString)
})
// Authentication (server-only)
const authenticateUser = createServerFn()
.inputValidator(z.object({ token: z.string() }))
.handler(async ({ data }) => {
const jwtSecret = process.env.JWT_SECRET // Server-only
return jwt.verify(data.token, jwtSecret)
})
```
--------------------------------
### Configure New Relic Agent for SSR (Node.js)
Source: https://tanstack.com/start/latest/docs/framework/react/guide/observability.md
Defines the New Relic agent configuration for a Node.js application, including application name, license key, and distributed tracing settings.
```js
// newrelic.js - New Relic agent configuration
exports.config = {
app_name: ['YourTanStackApp'], // Your application name in New Relic
license_key: 'YOUR_NEW_RELIC_LICENSE_KEY', // Your New Relic license key
agent_enabled: true,
distributed_tracing: { enabled: true },
span_events: { enabled: true },
transaction_events: { enabled: true },
// Additional default settings
}
```