Documentation Index Fetch the complete documentation index at: https://mintlify.com/tanstack/router/llms.txt
Use this file to discover all available pages before exploring further.
TanStack Start applications can be deployed to various hosting platforms. The deployment process varies based on whether you’re building a traditional Single Page Application (SPA) or using server-side rendering (SSR).
Deployment Modes
TanStack Start supports multiple deployment modes:
Server-Side Rendering (SSR)
Full-stack applications with server rendering, streaming, and server functions:
Node.js servers - Express, Fastify, or standalone
Serverless platforms - Vercel, Netlify, AWS Lambda
Edge runtime - Cloudflare Workers, Deno Deploy
Containerized - Docker on any cloud platform
Static Site Generation (SSG)
Pre-render pages at build time for static hosting:
Great for content-heavy sites
Deploy to CDNs for global distribution
No server runtime required
Single Page Application (SPA)
Client-side only applications:
Traditional SPA deployment
Any static file hosting
Requires client-side routing configuration
Cloudflare Pages
Deploy SSR applications to Cloudflare’s edge network:
Install adapter
npm install @tanstack/start-adapter-cloudflare-pages
Configure the adapter
import { createStartHandler } from '@tanstack/react-start-server'
import { defaultStreamHandler } from '@tanstack/react-start-server'
export default createStartHandler ( defaultStreamHandler )
Deploy
npm run build
npx wrangler pages publish .output/public
Configuration:
name = "my-tanstack-start-app"
compatibility_date = "2024-01-01"
[ build ]
command = "npm run build"
[ site ]
bucket = ".output/public"
Vercel
Deploy to Vercel’s serverless platform:
Configure build
{
"buildCommand" : "npm run build" ,
"outputDirectory" : ".output/public" ,
"devCommand" : "npm run dev" ,
"installCommand" : "npm install"
}
Vercel automatically detects TanStack Start projects and configures them correctly.
Netlify
Deploy to Netlify with edge functions:
Create configuration
[ build ]
command = "npm run build"
publish = ".output/public"
[[ redirects ]]
from = "/*"
to = "/.netlify/functions/server"
status = 200
Node.js Server
Deploy to any Node.js environment:
Start the server
node .output/server/index.mjs
Custom server:
import { createStartHandler } from '@tanstack/react-start-server'
import { defaultStreamHandler } from '@tanstack/react-start-server'
import express from 'express'
const app = express ()
const handler = createStartHandler ( defaultStreamHandler )
app . use ( express . static ( '.output/public' ))
app . use ( handler )
app . listen ( 3000 , () => {
console . log ( 'Server running on http://localhost:3000' )
})
Docker
Containerize your application:
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm ci
# Copy source and build
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
# Copy built application
COPY --from=builder /app/.output ./.output
COPY --from=builder /app/package*.json ./
# Install production dependencies only
RUN npm ci --production
EXPOSE 3000
CMD [ "node" , ".output/server/index.mjs" ]
Build and run:
docker build -t my-tanstack-app .
docker run -p 3000:3000 my-tanstack-app
Static Hosting (SPA Mode)
Deploy as a static site:
Configure redirects
For client-side routing, redirect all requests to index.html: Netlify (public/_redirects):Vercel (vercel.json):{
"rewrites" : [
{ "source" : "/(.*)" , "destination" : "/index.html" }
]
}
Nginx :location / {
try_files $ uri $ uri / /index.html;
}
Deploy static files
Upload the .output/public directory to your static hosting provider.
Environment Variables
Manage environment-specific configuration:
Build-Time Variables
Vite exposes variables prefixed with VITE_:
VITE_API_URL = https://api.example.com
VITE_ANALYTICS_ID = abc123
const apiUrl = import . meta . env . VITE_API_URL
Runtime Variables (Server-Side)
Access variables in server functions and loaders:
const dbConnection = createServerFn (). handler ( async () => {
const dbUrl = process . env . DATABASE_URL
return connectToDatabase ( dbUrl )
})
Security: Server-side environment variables are never exposed to the client.
Vercel:
vercel env add DATABASE_URL
Netlify:
netlify env:set DATABASE_URL "postgresql://..."
Cloudflare:
wrangler secret put DATABASE_URL
Asset Management
TanStack Start automatically handles asset optimization:
Asset Manifest
The build generates a manifest of all assets:
{
"app.css" : "/assets/app-abc123.css" ,
"app.js" : "/assets/app-def456.js" ,
"logo.svg" : "/assets/logo-ghi789.svg"
}
The server uses this manifest to inject correct asset URLs.
CDN Integration
Transform asset URLs to use a CDN:
import { createStartHandler } from '@tanstack/react-start-server'
import { defaultStreamHandler } from '@tanstack/react-start-server'
export default createStartHandler ({
handler: defaultStreamHandler ,
transformAssetUrls: 'https://cdn.example.com' ,
})
Dynamic CDN selection:
export default createStartHandler ({
handler: defaultStreamHandler ,
transformAssetUrls: {
transform : ({ url }) => {
const region = getRequest (). headers . get ( 'x-region' ) || 'us'
return `https://cdn- ${ region } .example.com ${ url } `
},
cache: false , // Transform per-request
} ,
})
Static Assets
Place static assets in the public/ directory:
project/
├── public/
│ ├── favicon.ico
│ ├── robots.txt
│ └── images/
│ └── logo.png
Reference them with absolute paths:
< img src = "/images/logo.png" alt = "Logo" />
Code Splitting
TanStack Router automatically code-splits by route:
// Each route becomes a separate chunk
export const Route = createFileRoute ( '/dashboard' )({
component: Dashboard ,
})
Compression
Enable compression in your server:
import compression from 'compression'
app . use ( compression ())
Caching Strategies
Set appropriate cache headers:
export const Route = createFileRoute ( '/posts' )({
loader : async () => {
setResponseHeader ( 'Cache-Control' , 'public, max-age=3600, stale-while-revalidate=86400' )
return { posts: await fetchPosts () }
},
})
Cache strategies:
Static assets : public, max-age=31536000, immutable
API responses : public, max-age=60, stale-while-revalidate=300
HTML pages : public, max-age=0, must-revalidate
Preloading
Preload critical resources:
export const Route = createFileRoute ( '/' )({
component: Home ,
loader : async () => {
// Preload critical data
const [ hero , posts ] = await Promise . all ([
fetchHero (),
fetchPosts ({ limit: 5 })
])
return { hero , posts }
}
})
Monitoring and Observability
Error Tracking
Integrate error tracking:
import * as Sentry from '@sentry/react'
if ( process . env . NODE_ENV === 'production' ) {
Sentry . init ({
dsn: process . env . SENTRY_DSN ,
environment: process . env . NODE_ENV ,
})
}
Track Core Web Vitals:
import { onCLS , onFID , onLCP } from 'web-vitals'
function sendToAnalytics ( metric ) {
// Send to your analytics endpoint
fetch ( '/api/analytics' , {
method: 'POST' ,
body: JSON . stringify ( metric ),
})
}
onCLS ( sendToAnalytics )
onFID ( sendToAnalytics )
onLCP ( sendToAnalytics )
Logging
Implement structured logging:
import { createServerFn } from '@tanstack/start-client-core'
const serverFn = createServerFn ()
. method ( 'POST' )
. handler ( async ({ data }) => {
console . log ({
level: 'info' ,
message: 'Processing request' ,
data ,
timestamp: new Date (). toISOString (),
})
// ...
})
Best Practices
Use environment variables for configuration
Never hardcode secrets or environment-specific values: // ✗ Bad
const apiKey = 'sk_live_abc123'
// ✓ Good
const apiKey = process . env . API_KEY
Reduce transfer size with gzip or brotli compression: import compression from 'compression'
app . use ( compression ())
Use appropriate cache headers for different content types: // Static assets - cache forever
res . setHeader ( 'Cache-Control' , 'public, max-age=31536000, immutable' )
// Dynamic content - cache with revalidation
res . setHeader ( 'Cache-Control' , 'public, max-age=60, stale-while-revalidate=300' )
Monitor application health
Set up health check endpoints: app . get ( '/health' , ( req , res ) => {
res . json ({ status: 'ok' , timestamp: Date . now () })
})
Test production builds locally
Always test production builds before deploying: npm run build
npm run preview
Use CDN for static assets
Serve assets from a CDN for global distribution: export default createStartHandler ({
handler: defaultStreamHandler ,
transformAssetUrls: 'https://cdn.example.com' ,
})
Troubleshooting
Build Failures
Issue: Build fails with module errors
Solution: Check that all dependencies are installed and versions are compatible:
rm -rf node_modules package-lock.json
npm install
Runtime Errors
Issue: Application crashes on startup
Solution: Check environment variables are set correctly:
node -e "console.log(process.env)"
Issue: Slow page loads
Solution:
Enable streaming: defaultStreamHandler
Add Suspense boundaries for slow components
Implement proper caching strategies
Use CDN for static assets
Server Rendering Learn how SSR works
Streaming Optimize with streaming
Deployment Guide Complete deployment guide
Static Generation Pre-render pages at build time