This guide covers deploying TanStack Router applications to popular hosting platforms.
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.
Create a public/_redirects file (or _redirects in your build output):
/* /index.html 200
Create a netlify.toml file in your project root:
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[build]
publish = "dist"
command = "npm run build"
[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 = 200
Create a public/_redirects file:
/* /index.html 200
Create a public/_routes.json file for more control:
{
"version": 1,
"include": ["/*"],
"exclude": ["/api/*"]
}
Create functions/_middleware.ts for SSR support:
export const onRequest: PagesFunction = async (context) => {
// Handle SSR requests
return await handleSSR(context)
}
# Install Wrangler
npm install -g wrangler
# Deploy
wrangler pages publish dist --project-name=my-app
Create a vercel.json file in your project root:
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}
If using TanStack Start with SSR, use this configuration instead:
{
"functions": {
"app/server.ts": {
"runtime": "nodejs18.x"
}
},
"routes": [
{
"src": "/(.*)",
"dest": "/api/server"
}
]
}
Ensure your package.json has the correct build script:
{
"scripts": {
"build": "vite build",
"preview": "vite preview"
}
}
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
GitHub Pages requires a 404.html file that duplicates index.html:
# After building
cp dist/index.html dist/404.html
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',
},
})
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: ./dist
{
"hosting": {
"public": "dist",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
# Install Firebase CLI
npm install -g firebase-tools
# Login and initialize
firebase login
firebase init hosting
# Build and deploy
npm run build
firebase deploy
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>
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";
}
}
# 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;"]
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
docker build -t my-tanstack-app .
docker run -p 80:80 my-tanstack-app
Before deploying, ensure you have:
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.
Problem: App works in development but shows errors in production.
Solutions:
export default defineConfig({
base: '/my-app/', // Match your deployment path
})
export default defineConfig({
build: {
outDir: 'dist', // Must match hosting platform setting
},
})
# .env
VITE_API_URL=https://api.example.com
Problem: App loads but styling is broken or JavaScript fails to load.
Solutions:
After deployment, you might want to: