How to Deploy TanStack Router to Production
This guide covers deploying TanStack Router applications to popular hosting platforms.
Quick Start#
Single Page Applications (SPAs) need special server configuration to handle client-side routing. Configure your hosting platform to serve index.html for all routes, allowing TanStack Router to handle navigation.
Netlify Deployment#
1. Create _redirects File#
Create a public/_redirects file (or _redirects in your build output):
/* /index.html 2002. Alternative: netlify.toml#
Create a netlify.toml file in your project root:
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[build]
publish = "dist"
command = "npm run build"3. For TanStack Start (SSR)#
[build]
publish = ".output/public"
command = "npm run build"
[functions]
directory = ".output/server"
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/server"
status = 200
[[redirects]]
from = "/*"
to = "/index.html"
status = 200Cloudflare Pages#
1. Create _redirects File#
Create a public/_redirects file:
/* /index.html 2002. Alternative: _routes.json#
Create a public/_routes.json file for more control:
{
"version": 1,
"include": ["/*"],
"exclude": ["/api/*"]
}3. For TanStack Start (SSR)#
Create functions/_middleware.ts for SSR support:
export const onRequest: PagesFunction = async (context) => {
// Handle SSR requests
return await handleSSR(context)
}4. Deploy via Git#
- Connect your GitHub repository to Cloudflare Pages
- Set build settings:
- Build command: npm run build
- Build output directory: dist
- Root directory: (leave empty)
5. Deploy via Wrangler CLI#
# Install Wrangler
npm install -g wrangler
# Deploy
wrangler pages publish dist --project-name=my-appVercel Deployment#
1. Create vercel.json#
Create a vercel.json file in your project root:
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}2. For TanStack Start (SSR) Applications#
If using TanStack Start with SSR, use this configuration instead:
{
"functions": {
"app/server.ts": {
"runtime": "nodejs18.x"
}
},
"routes": [
{
"src": "/(.*)",
"dest": "/api/server"
}
]
}3. Build Configuration#
Ensure your package.json has the correct build script:
{
"scripts": {
"build": "vite build",
"preview": "vite preview"
}
}4. Deploy#
# Install Vercel CLI
npm i -g vercel
# Deploy
vercelGitHub Pages#
1. Create 404.html#
GitHub Pages requires a 404.html file that duplicates index.html:
# After building
cp dist/index.html dist/404.html2. Update vite.config.js#
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
export default defineConfig({
base: '/your-repo-name/', // Replace with your repository name
plugins: [
tanstackRouter({
target: 'react',
autoCodeSplitting: true,
}),
react(),
],
build: {
outDir: 'dist',
},
})3. GitHub Actions Workflow#
Create .github/workflows/deploy.yml:
name: Deploy to GitHub Pages
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Create 404.html
run: cp dist/index.html dist/404.html
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./distFirebase Hosting#
1. Create firebase.json#
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}2. Deploy#
# Install Firebase CLI
npm install -g firebase-tools
# Login and initialize
firebase login
firebase init hosting
# Build and deploy
npm run build
firebase deployApache Server#
Create a .htaccess file in your build output directory:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>Nginx#
Add this configuration to your Nginx server block:
server {
listen 80;
server_name your-domain.com;
root /path/to/your/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# Optional: Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}Docker Deployment#
1. Create Dockerfile#
# Build stage
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]2. Create nginx.conf#
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}3. Build and Run#
docker build -t my-tanstack-app .
docker run -p 80:80 my-tanstack-appProduction Checklist#
Before deploying, ensure you have:
- Created hosting platform configuration file
- Set correct base path if deploying to subdirectory
- Configured environment variables with VITE_ prefix
- Tested all routes by direct URL access
- Verified static assets load correctly
Common Problems#
404 Errors on Page Refresh#
Problem: Routes work when navigating within the app, but refreshing the page shows 404.
Cause: The server looks for files like /about/index.html which don't exist in SPAs.
Solution: Add the configuration files shown above for your hosting platform.
App Works Locally But Breaks When Deployed#
Problem: App works in development but shows errors in production.
Solutions:
- Subdirectory deployment: Configure base path in vite.config.js:js
export default defineConfig({ base: '/my-app/', // Match your deployment path }) - Build output mismatch: Ensure build directory matches hosting config:js
export default defineConfig({ build: { outDir: 'dist', // Must match hosting platform setting }, }) - Environment variables: Prefix with VITE_ and rebuild:shell
# .env VITE_API_URL=https://api.example.com
Assets Not Loading (CSS/JS 404s)#
Problem: App loads but styling is broken or JavaScript fails to load.
Solutions:
- Check build output directory in hosting configuration
- Verify public path configuration in Vite
- Ensure static file serving is properly configured
Common Next Steps#
After deployment, you might want to:
- How to Set Up Basic Authentication - Secure your application with auth
- Migrate from React Router v7 - Complete migration guide if you're coming from React Router
- How to Set Up Server-Side Rendering (SSR)
Related Resources#
- Deployment Examples - Official examples