| name | tanstack-start-project-setup |
| description | Set up and configure TanStack Start projects. Use when creating new projects, configuring the router, setting up TanStack Query integration, or configuring build settings. |
| license | Apache-2.0 |
| metadata | {"author":"tanstack","version":"1.0"} |
TanStack Start Project Setup
TanStack Start is a full-stack React framework built on TanStack Router, Vinxi, and Vite.
When to Use
- Creating a new TanStack Start project
- Configuring router settings
- Setting up TanStack Query
- Adding TypeScript configuration
- Configuring for Netlify deployment
Quick Start
npx create-tanstack-start@latest my-app
npx create-tanstack-start@latest my-app --template basic
Project Structure
my-app/
├── src/
│ ├── routes/
│ │ ├── __root.tsx # Root layout
│ │ ├── index.tsx # Home page (/)
│ │ └── ...
│ ├── server/
│ │ └── *.functions.ts # Server functions
│ ├── components/
│ ├── lib/
│ ├── router.tsx # Router configuration
│ └── routeTree.gen.ts # Auto-generated
├── public/
├── app.config.ts # TanStack Start config
├── package.json
├── tsconfig.json
└── netlify.toml # Netlify deployment
Essential Files
app.config.ts
import { defineConfig } from '@tanstack/react-start/config';
export default defineConfig({
vite: {
plugins: [],
},
server: {
preset: 'netlify',
},
tsr: {
routesDirectory: './src/routes',
generatedRouteTree: './src/routeTree.gen.ts',
},
});
router.tsx
import { createRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen';
export function getRouter() {
const router = createRouter({
routeTree,
scrollRestoration: true,
defaultPreload: 'intent',
defaultPreloadStaleTime: 0,
defaultErrorComponent: ({ error }) => (
<div>Error: {error.message}</div>
),
defaultPendingComponent: () => <div>Loading...</div>,
defaultNotFoundComponent: () => <div>Not Found</div>,
});
return router;
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof getRouter>;
}
}
Root Route (__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: 'My TanStack Start App' },
{ name: 'description', content: 'Built with TanStack Start' },
],
links: [
{ rel: 'stylesheet', href: '/styles.css' },
{ rel: 'icon', href: '/favicon.ico' },
],
}),
component: RootComponent,
});
function RootComponent() {
return (
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
);
}
TanStack Query Integration
Installation
npm install @tanstack/react-query
Setup
import { createRouter } from '@tanstack/react-router';
import { QueryClient } from '@tanstack/react-query';
import { routeTree } from './routeTree.gen';
export function getRouter() {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60,
gcTime: 1000 * 60 * 5,
},
},
});
const router = createRouter({
routeTree,
context: {
queryClient,
},
});
return router;
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof getRouter>;
}
}
Root with Query Provider
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
export const Route = createRootRouteWithContext<{
queryClient: QueryClient;
}>()({
component: RootComponent,
});
function RootComponent() {
const { queryClient } = Route.useRouteContext();
return (
<QueryClientProvider client={queryClient}>
<html lang="en">
<head>
<HeadContent />
</head>
<body>
<Outlet />
<Scripts />
<ReactQueryDevtools />
</body>
</html>
</QueryClientProvider>
);
}
TypeScript Configuration
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"noEmit": true,
"isolatedModules": true,
"esModuleInterop": true,
"skipLibCheck": true,
"paths": {
"~/*": ["./src/*"]
}
},
"include": ["src/**/*", "app.config.ts"],
"exclude": ["node_modules"]
}
Netlify Deployment
netlify.toml
[build]
command = "npm run build"
publish = ".output/public"
[build.environment]
NODE_VERSION = "20"
[functions]
directory = ".output/server"
app.config.ts for Netlify
import { defineConfig } from '@tanstack/react-start/config';
export default defineConfig({
server: {
preset: 'netlify',
},
});
Environment Variables
.env Files
DATABASE_URL=postgres://localhost:5432/mydb
VITE_APP_NAME=My App
DATABASE_URL=postgres://prod-server:5432/mydb
VITE_APP_NAME=My App
Accessing Variables
const dbUrl = process.env.DATABASE_URL;
const appName = import.meta.env.VITE_APP_NAME;
CSS/Styling Setup
Tailwind CSS
npm install tailwindcss @tailwindcss/vite
import { defineConfig } from '@tanstack/react-start/config';
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
vite: {
plugins: [tailwindcss()],
},
});
@import 'tailwindcss';
CSS Modules
import styles from './Component.module.css';
export function Component() {
return <div className={styles.container}>Hello</div>;
}
Development Scripts
{
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start",
"lint": "eslint src/",
"typecheck": "tsc --noEmit"
}
}
Recommended Package.json
{
"name": "my-tanstack-app",
"type": "module",
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start"
},
"dependencies": {
"@tanstack/react-query": "^5.0.0",
"@tanstack/react-router": "^1.0.0",
"@tanstack/react-start": "^1.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"vinxi": "^0.5.0",
"zod": "^3.23.0"
},
"devDependencies": {
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"typescript": "^5.6.0"
}
}
Database Setup (Drizzle)
npm install drizzle-orm@beta @netlify/database
npm install -D drizzle-kit@beta
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
dialect: 'postgresql',
schema: './db/schema.ts',
out: 'netlify/database/migrations',
});
import { drizzle } from 'drizzle-orm/netlify-db';
import * as schema from './schema';
export const db = drizzle({ schema });
Common Configurations
Custom 404 Page
export const Route = createRootRoute({
notFoundComponent: () => (
<div className="not-found">
<h1>404 - Page Not Found</h1>
<Link to="/">Go Home</Link>
</div>
),
});
Global Error Boundary
export const Route = createRootRoute({
errorComponent: ({ error, reset }) => (
<div className="error-page">
<h1>Something went wrong</h1>
<p>{error.message}</p>
<button onClick={reset}>Try Again</button>
</div>
),
});
Loading States
export const Route = createRootRoute({
pendingComponent: () => (
<div className="loading">
<span className="spinner" />
Loading...
</div>
),
});
Checklist for New Projects