TanStack Start Quickstart
TanStack Start is a new React framework currently in the Release Candidate stage. You can try it today but there might still be bug or issues.
To get setup quickly with Convex and TanStack Start run
npm create convex@latest -- -t tanstack-start
or follow the guide below.
To use Clerk with Convex and TanStack Start, see the TanStack Start + Clerk guide
Learn how to query data from Convex in a TanStack Start site.
- Create a TanStack Start site
Create a TanStack Start app using the
create-start-app
command:npx create-start-app@latest
- Install the Convex client and server library
To get started with Convex install the
convex
package and a few React Query-related packages.npm install convex @convex-dev/react-query @tanstack/react-router-with-query @tanstack/react-query
- Update app/routes/__root.tsx
Add a
QueryClient
to the router context to make React Query usable anywhere in the TanStack Start site.app/routes/__root.tsximport { QueryClient } from "@tanstack/react-query";
import { createRootRouteWithContext } from "@tanstack/react-router";
import { Outlet, Scripts, HeadContent } from "@tanstack/react-router";
import * as React from "react";
export const Route = createRootRouteWithContext<{
queryClient: QueryClient;
}>()({
head: () => ({
meta: [
{
charSet: "utf-8",
},
{
name: "viewport",
content: "width=device-width, initial-scale=1",
},
{
title: "TanStack Start Starter",
},
],
}),
component: RootComponent,
});
function RootComponent() {
return (
<RootDocument>
<Outlet />
</RootDocument>
);
}
function RootDocument({ children }: { children: React.ReactNode }) {
return (
<html>
<head>
<HeadContent />
</head>
<body>
{children}
<Scripts />
</body>
</html>
);
} - Update app/router.tsx
Replace the file
app/router.tsx
with these contents.This creates a
ConvexClient
and aConvexQueryClient
and wires in aConvexProvider
.app/router.tsximport { createRouter } from "@tanstack/react-router";
import { QueryClient } from "@tanstack/react-query";
import { routerWithQueryClient } from "@tanstack/react-router-with-query";
import { ConvexQueryClient } from "@convex-dev/react-query";
import { ConvexProvider } from "convex/react";
import { routeTree } from "./routeTree.gen";
export function getRouter() {
const CONVEX_URL = (import.meta as any).env.VITE_CONVEX_URL!;
if (!CONVEX_URL) {
console.error("missing envar VITE_CONVEX_URL");
}
const convexQueryClient = new ConvexQueryClient(CONVEX_URL);
const queryClient: QueryClient = new QueryClient({
defaultOptions: {
queries: {
queryKeyHashFn: convexQueryClient.hashFn(),
queryFn: convexQueryClient.queryFn(),
},
},
});
convexQueryClient.connect(queryClient);
const router = routerWithQueryClient(
createRouter({
routeTree,
defaultPreload: "intent",
context: { queryClient },
scrollRestoration: true,
Wrap: ({ children }) => (
<ConvexProvider client={convexQueryClient.convexClient}>
{children}
</ConvexProvider>
),
}),
queryClient,
);
return router;
} - Set up a Convex dev deployment
Next, run
npx convex dev
. This will prompt you to log in with GitHub, create a project, and save your production and deployment URLs.It will also create a
convex/
folder for you to write your backend API functions in. Thedev
command will then continue running to sync your functions with your dev deployment in the cloud.npx convex dev
- Create sample data for your database
In a new terminal window, create a
sampleData.jsonl
file with some sample data.sampleData.jsonl{"text": "Buy groceries", "isCompleted": true}
{"text": "Go for a swim", "isCompleted": true}
{"text": "Integrate Convex", "isCompleted": false} - Add the sample data to your database
Now that your project is ready, add a
tasks
table with the sample data into your Convex database with theimport
command.npx convex import --table tasks sampleData.jsonl
- Expose a database query
Add a new file
tasks.ts
in theconvex/
folder with a query function that loads the data.Exporting a query function from this file declares an API function named after the file and the export name,
api.tasks.get
.convex/tasks.tsimport { query } from "./_generated/server";
export const get = query({
args: {},
handler: async (ctx) => {
return await ctx.db.query("tasks").collect();
},
}); - Display the data in your app
Replace the file
app/routes/index.tsx
with these contents.The
useSuspenseQuery
hook renders the API functionapi.tasks.get
query result on the server initially, then it updates live in the browser.app/routes/index.tsximport { convexQuery } from "@convex-dev/react-query";
import { useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { api } from "../../convex/_generated/api";
export const Route = createFileRoute("/")({
component: Home,
});
function Home() {
const { data } = useSuspenseQuery(convexQuery(api.tasks.get, {}));
return (
<div>
{data.map(({ _id, text }) => (
<div key={_id}>{text}</div>
))}
</div>
);
} - Start the app
Start the app, open http://localhost:3000 in a browser, and see the list of tasks.
npm run dev
For more see the TanStack Start with Convex client documentation page.