Getting started
Examples
The same issue tracker built on TanStack Start, on the Next.js App Router, on React Router Framework Mode, and on TanStack Start with Effect, ready to open in CodeSandbox.
The repository has one app built four times: a small issue tracker on TanStack Start, on the Next.js App Router and on React Router Framework Mode, so the integrations can be compared side by side, and on TanStack Start again, written with Effect end to end. Each runs live on Vercel, and opens in CodeSandbox, which runs it on a cloud VM.
| Example | Framework | Source | Live | Try it |
|---|---|---|---|---|
| Issue tracker | TanStack Start | examples/tanstack-start | tanstack-start.raf-query.katt.dev | Open in CodeSandbox |
| Issue tracker | Next.js App Router | examples/nextjs | nextjs.raf-query.katt.dev | Open in CodeSandbox |
| Issue tracker | React Router Framework Mode | examples/react-router | react-router.raf-query.katt.dev | Open in CodeSandbox |
| Issue tracker | TanStack Start, Effect and Effect RPC | examples/tanstack-start-effect | tanstack-start-effect.raf-query.katt.dev | Open in CodeSandbox |
What they cover
Every feature in these docs appears somewhere in the app:
| Screen or action | Shows |
|---|---|
| Loader verb | The URL's first segment picks how loaders start queries: prefetch, ensure or fetch (/ensure/issues/3) |
| Progress bar along the top | The router's own pending state while ensure and fetch wait: useRouterState, useNavigation, or Next.js's useLinkStatus |
| Issue list with status filter and sort | Search params → loader → paged query, infinite scroll, whilePending: "previous", isPrevious dimming |
| Issue detail | Under prefetch the page opens onto skeletons for the title, body, and status; ensure and fetch wait for them |
| Comments under an issue | A paged query, streamed under prefetch, infinite scroll |
| Assignee card | The loader or server component starts the assignee by issue id, next to the issue, so neither waits on the other |
| Inline-edit title and body; change status from the list | Form Actions / transitions, useOptimistic and await qc.invalidate(...) |
Data comes from an in-memory database with artificial latency (400 ms ± 50% per call), behind a small REST API the TanStack Start, Next.js and React Router apps share. The top bar's Loader select switches the loader verb, and keeps the page you are on. On Next.js and React Router every navigation renders on the server with a new client, so ensure waits as long as fetch there; in the TanStack Start apps, loaders run in the browser and ensure shows cached data at once. The top bar sets that latency, how links prefetch, and how long cached data stays fresh. Reset clears those choices and the query cache, then reloads. The Effect app serves it as an Effect RPC group instead: its queryFns, loaders and form actions are Effects, and they catch its typed errors with Effect.catchTag. Data the server loads for the first render streams in with the HTML; later loads show up in the browser's network tab.
Run them locally
git clone https://github.com/KATT/raf-query
cd raf-query
pnpm install
pnpm dev:start # TanStack Start on http://localhost:3000
pnpm dev:next # Next.js on http://localhost:3001
pnpm dev:react-router # React Router on http://localhost:3006
pnpm dev:effect # TanStack Start with Effect on http://localhost:3005Demos in these docs
The guides embed live demos that run entirely in your browser. Each has its own query client and a fake server with adjustable latency, and shows its requests as a waterfall and its cache entries as they change. Expand opens the same demo in a dialog next to the devtools panel. Good places to start:
- Starting queries: prefetch, ensure and fetch
- Caching: fresh, stale, inactive and garbage-collected entries
- URL state and pagination:
whilePending - Mutations: optimistic updates that roll back
- Request waterfalls: chained versus parallel loading