A modern chat template built with TanStack Router and Claude AI integration features a clean and responsive interface.
⚡ View demo: https://tanstack-starter.netlify.app/
- Deploy to Netlify
- Features
- Project Structure
- Architecture
- Getting Started
- Styling
- Error Monitoring
- Environment Configuration
- Routing
- Data Fetching
- State Management
- Learn More
Want to deploy immediately? Click this button
Clicking this button will create a new repo for you that looks exactly like this one, and sets that repo up immediately for deployment on Netlify.
- 🤖 Powered by Claude 3.5 Sonnet
- 📝 Rich markdown formatting with syntax highlighting
- 🎯 Customizable system prompts for tailored AI behavior
- 🔄 Real-time message updates and streaming responses
- 🎨 Modern UI with Tailwind CSS and Lucide icons
- 🔍 Conversation management
- 🔐 API key management
- 📋 Markdown rendering with code highlighting
- Frontend Framework: React 19 with TanStack Start
- Routing: TanStack Router
- State Management: TanStack Store
- Database: Convex (optional)
- Styling: Tailwind CSS 4
- AI Integration: Anthropic's Claude API
- Build Tool: Vite 6 with Vinxi
- Node.js v20.9+
- (optional) nvm for Node version management
- Anthropic Claude API
- (optional) Convex Account for database storage
The project follows a modular structure for better organization and maintainability:
tanstack-template/
├── convex/ # Convex database schema and functions (optional)
├── public/ # Static assets
├── src/
│ ├── components/ # Reusable UI components
│ ├── routes/ # TanStack Router route definitions
│ ├── store/ # TanStack Store state management
│ ├── utils/ # Utility functions and helpers
│ ├── api.ts # API client configuration
│ ├── client.tsx # Client-side entry point
│ ├── convex.tsx # Convex client configuration
│ ├── router.tsx # Router configuration
│ ├── sentry.ts # Sentry error monitoring setup
│ ├── ssr.tsx # Server-side rendering setup
│ └── styles.css # Global styles
├── .env.example # Example environment variables
├── app.config.ts # Application configuration
├── package.json # Project dependencies and scripts
├── postcss.config.ts # PostCSS configuration for Tailwind
├── tsconfig.json # TypeScript configuration
└── vite.config.js # Vite bundler configuration
- src/components/: Contains all reusable UI components used throughout the application
- src/routes/: Contains route definitions using TanStack Router's file-based routing
- src/store/: Contains state management logic using TanStack Store
- convex/: Contains Convex database schema and functions (if using Convex for persistence)
Follow these steps to set up and run the project locally:
-
Clone the repository
git clone https://github.com/netlify-templates/tanstack-template.git cd tanstack-template
-
Install dependencies
npm install
-
Set up environment variables
cp .env.example .env
Then edit the
.env
file with your credentials:- Required: Add your Anthropic API key (
VITE_ANTHROPIC_API_KEY
) - Optional: Add Convex URL if using database features (
VITE_CONVEX_URL
) - Optional: Add Sentry credentials for error monitoring (
VITE_SENTRY_DSN
,SENTRY_AUTH_TOKEN
)
- Required: Add your Anthropic API key (
-
Start the development server
npm run dev
The application should now be running at http://localhost:3000
-
Node.js version: Ensure you're using Node.js v20.9 or higher. You can check your version with
node -v
.# Using nvm to install and use the correct Node version nvm install 20.9 nvm use 20.9
-
API Key Issues: If you encounter errors related to the Anthropic API, verify that your API key is correctly set in the
.env
file and that you have sufficient credits in your Anthropic account. -
Port Conflicts: If port 3000 is already in use, the development server will automatically try to use the next available port. Check your terminal output for the correct URL.
-
Convex Setup (Optional): If you're using Convex for database functionality:
npx convex dev
This will start the Convex development server alongside your application.
To build this application for production:
npm run build
To preview the production build:
npm run serve
This project uses Tailwind CSS v4 for styling.
This project uses Sentry for error monitoring and performance tracking. Sentry integration is optional and the project will run normally without Sentry configuration.
To set up Sentry:
- Add your Sentry DSN and Auth Token to your
.env
file (created during the Getting Started steps)
# .env file
VITE_SENTRY_DSN=your-sentry-dsn-here
SENTRY_AUTH_TOKEN=your-sentry-auth-token-here
If the Sentry environment variables are not defined, the application will run without error monitoring.
You can generate and manage your Anthropic API keys through the Anthropic Console.
# .env file
VITE_ANTHROPIC_API_KEY=your_anthropic_api_key
For persistent storage of conversations:
- Create a Convex account at dashboard.convex.dev
- Create a new project in the Convex dashboard
- Run
npx convex dev
in your project directory to set up Convex - Add your Convex deployment URL to the
.env
file
# .env file
VITE_CONVEX_URL=your_convex_deployment_url
This project uses TanStack Router. The initial setup is a file based router. Which means that the routes are managed as files in src/routes
.
To add a new route to your application just add another a new file in the ./src/routes
directory.
TanStack will automatically generate the content of the route file for you.
Now that you have two routes you can use a Link
component to navigate between them.
To use SPA (Single Page Application) navigation you will need to import the Link
component from @tanstack/react-router
.
import { Link } from "@tanstack/react-router";
Then anywhere in your JSX you can use it like so:
<Link to="/about">About</Link>
This will create a link that will navigate to the /about
route.
More information on the Link
component can be found in the Link documentation.
In the File Based Routing setup the layout is located in src/routes/__root.tsx
. Anything you add to the root route will appear in all the routes. The route content will appear in the JSX where you use the <Outlet />
component.
Here is an example layout that includes a header:
import { createRootRoute, Outlet } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
import { Link } from "@tanstack/react-router";
export const Route = createRootRoute({
component: () => (
<>
<header>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
</header>
<Outlet />
<TanStackRouterDevtools />
</>
),
})
The <TanStackRouterDevtools />
component is not required so you can remove it if you don't want it in your layout.
More information on layouts can be found in the Layouts documentation.
There are multiple ways to fetch data in your application. You can use the loader
functionality built into TanStack Router to load the data for a route before it's rendered.
For example:
const peopleRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/people",
loader: async () => {
const response = await fetch("https://swapi.dev/api/people");
return response.json() as Promise<{
results: {
name: string;
}[];
}>;
},
component: () => {
const data = peopleRoute.useLoaderData();
return (
<ul>
{data.results.map((person) => (
<li key={person.name}>{person.name}</li>
))}
</ul>
);
},
});
Loaders simplify your data fetching logic dramatically. Check out more information in the Loader documentation.
This project uses TanStack Store for local state management. The store files are located in the src/store
directory. For persistent storage, the project can optionally use Convex as a backend database.
Here's a simple example of how to use TanStack Store:
import { useStore } from "@tanstack/react-store";
import { Store } from "@tanstack/store";
const countStore = new Store(0);
function Counter() {
const count = useStore(countStore);
return (
<div>
<button onClick={() => countStore.setState((n) => n + 1)}>
Increment - {count}
</button>
</div>
);
}
One of the many nice features of TanStack Store is the ability to derive state from other state. That derived state will update when the base state updates.
import { useStore } from "@tanstack/react-store";
import { Store, Derived } from "@tanstack/store";
const countStore = new Store(0);
const doubledStore = new Derived({
fn: () => countStore.state * 2,
deps: [countStore],
});
doubledStore.mount();
function Counter() {
const count = useStore(countStore);
const doubledCount = useStore(doubledStore);
return (
<div>
<button onClick={() => countStore.setState((n) => n + 1)}>
Increment - {count}
</button>
<div>Doubled - {doubledCount}</div>
</div>
);
}
You can find out everything you need to know on how to use TanStack Store in the TanStack Store documentation.
- Explore more about deploying with Netlify in the Netlify documentation.
- You can learn more about TanStack in the TanStack documentation.
- Learn more about integrating AI with Anthropic's Claude API in the Anthropic API documentation.
- Learn about using Convex for database storage in the Convex documentation.