
Tanstack Start Project Setup
- 1 installs
- 3 repo stars
- Updated August 3, 2026
- netlify/swar-templates
Sets up and configures a new TanStack Start project including router config, TanStack Query, TypeScript, and the app.config.ts server preset for Netlify.
About
Bootstraps TanStack Start projects and configures the router, TanStack Query integration, project structure, and app.config.ts build/server settings. A developer uses it when creating a new full-stack React app or configuring it for Netlify deployment.
- create-tanstack-start scaffolding and standard project structure
- app.config.ts with Netlify server preset and router config
Tanstack Start Project Setup by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,912 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/netlify/swar-templates --skill tanstack-start-project-setupAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 3 |
| Last updated | August 3, 2026 |
| Repository | netlify/swar-templates ↗ |
What it does
Sets up and configures a new TanStack Start project including router config, TanStack Query, TypeScript, and the app.config.ts server preset for Netlify.
Files
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
# Create new project
npx create-tanstack-start@latest my-app
# Or with specific template
npx create-tanstack-start@latest my-app --template basicProject 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 deploymentEssential Files
app.config.ts
// app.config.ts
import { defineConfig } from '@tanstack/react-start/config';
export default defineConfig({
// Vite configuration
vite: {
// Add Vite plugins here
plugins: [],
},
// Server configuration
server: {
// Server preset (netlify, vercel, node, etc.)
preset: 'netlify',
},
// Router configuration
tsr: {
// Route file location
routesDirectory: './src/routes',
// Generated route tree location
generatedRouteTree: './src/routeTree.gen.ts',
},
});router.tsx
// src/router.tsx
import { createRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen';
export function getRouter() {
const router = createRouter({
routeTree,
// Enable scroll restoration
scrollRestoration: true,
// Preload on hover
defaultPreload: 'intent',
// Preload stale time
defaultPreloadStaleTime: 0,
// Default error component
defaultErrorComponent: ({ error }) => (
<div>Error: {error.message}</div>
),
// Default pending component
defaultPendingComponent: () => <div>Loading...</div>,
// Default not found component
defaultNotFoundComponent: () => <div>Not Found</div>,
});
return router;
}
// Type registration for full type safety
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof getRouter>;
}
}Root Route (__root.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: '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-querySetup
// src/router.tsx
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, // 1 minute
gcTime: 1000 * 60 * 5, // 5 minutes
},
},
});
const router = createRouter({
routeTree,
context: {
queryClient,
},
});
return router;
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof getRouter>;
}
}Root with Query Provider
// src/routes/__root.tsx
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
// tsconfig.json
{
"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 (auto-configured by TanStack Start)
[functions]
directory = ".output/server"app.config.ts for Netlify
// app.config.ts
import { defineConfig } from '@tanstack/react-start/config';
export default defineConfig({
server: {
preset: 'netlify',
},
});Environment Variables
.env Files
# .env (local development)
DATABASE_URL=postgres://localhost:5432/mydb
VITE_APP_NAME=My App
# .env.production (production)
DATABASE_URL=postgres://prod-server:5432/mydb
VITE_APP_NAME=My AppAccessing Variables
// Server-side (server functions, loaders on server)
const dbUrl = process.env.DATABASE_URL;
// Client-side (must be prefixed with VITE_)
const appName = import.meta.env.VITE_APP_NAME;CSS/Styling Setup
Tailwind CSS
npm install tailwindcss @tailwindcss/vite// app.config.ts
import { defineConfig } from '@tanstack/react-start/config';
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
vite: {
plugins: [tailwindcss()],
},
});/* src/styles.css */
@import 'tailwindcss';CSS Modules
// Component.tsx
import styles from './Component.module.css';
export function Component() {
return <div className={styles.container}>Hello</div>;
}Development Scripts
// package.json
{
"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 @neondatabase/serverless
npm install -D drizzle-kit// drizzle.config.ts
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});// src/db/index.ts
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
import * as schema from './schema';
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });Common Configurations
Custom 404 Page
// src/routes/__root.tsx
export const Route = createRootRoute({
notFoundComponent: () => (
<div className="not-found">
<h1>404 - Page Not Found</h1>
<Link to="/">Go Home</Link>
</div>
),
});Global Error Boundary
// src/routes/__root.tsx
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
// src/routes/__root.tsx
export const Route = createRootRoute({
pendingComponent: () => (
<div className="loading">
<span className="spinner" />
Loading...
</div>
),
});Checklist for New Projects
- [ ] Create project with
create-tanstack-start - [ ] Configure
app.config.tswith Netlify preset - [ ] Set up TypeScript paths (
~/) - [ ] Configure TanStack Query if needed
- [ ] Set up CSS solution (Tailwind recommended)
- [ ] Create
.envfor local development - [ ] Configure
netlify.tomlfor deployment - [ ] Set up database if needed (Drizzle + Neon)
- [ ] Add ESLint configuration
- [ ] Set environment variables in Netlify dashboard