# TanStack Start

Wire Rindle into TanStack Start with one adapter: `createRindleTanStack` returns the `Provider` that hands off from dehydrated SSR seed to the live wasm engine, and the `loader` that preloads named queries local-first.

`@rindle/tanstack`'s `createRindleTanStack({ schema, boot, preload })` is the whole binding: it
returns a **`Provider`** (the dehydrated-seed → live-wasm handoff) and a **`loader`** (preload +
retain for named queries). You mount the provider once at the router root and use the loader per
route.

## In the wild — tantaman.github.io

The adapter is set up once. `preload` is server-only (it reaches the authority in-process — see
[server rendering](/docs/ssr)); the wrapped `loader` boots the browser client before any
context-scoped named query builds its AST, and defaults `until: "present"` so routes are local-first:

```ts
// src/rindle-tanstack.ts
const integration = createRindleTanStack({
  schema,
  boot: bootClient,
  preload: async (queries) => {
    // Keep the authority/daemon client out of the browser graph. This callback only runs from a
    // server route loader; the adapter's client path calls `bootClient().ensure(...)` instead.
    const { preloadRindle } = await import("./ssr.ts");
    return preloadRindle([...queries]);
  },
});

// Route entry is local-first by default: if the exact view already has useful rows in the wasm
// store, commit the navigation immediately and let its retained server subscription revalidate.
function loader<Context extends RindleLoaderContext = RindleLoaderContext>(
  options: RindleRouteLoaderOptions<Context>,
): RindleRouteLoader<Context> {
  const routeLoader = integration.loader<Context>({ ...options, until: options.until ?? "present" });
  return {
    ...routeLoader,
    handler: async (context) => {
      // Boot first so context-scoped named queries build their local AST from the same principal
      // as the live client.
      if (typeof window !== "undefined") await bootClient();
      return routeLoader.handler(context);
    },
  };
}

export const rindle: typeof integration = { ...integration, loader };
```

*[`rindle-site/src/rindle-tanstack.ts` L15–48](https://github.com/tantaman/tantaman.github.io/blob/5889c6d72add4bd2825230223130fe896ceac4e3/rindle-site/src/rindle-tanstack.ts#L15-L48) · tantaman.github.io*

The **provider** wraps the router `Outlet` once at the root
([`__root.tsx` L48–56](https://github.com/tantaman/tantaman.github.io/blob/5889c6d72add4bd2825230223130fe896ceac4e3/rindle-site/src/routes/__root.tsx#L48-L56)),
and a route **reads** its query with `useRoot`:

```tsx
// src/routes/_shell.$slug.tsx
const [post, { status }] = useRoot(postQuery, slug);
```

*[`rindle-site/src/routes/_shell.$slug.tsx` L43](https://github.com/tantaman/tantaman.github.io/blob/5889c6d72add4bd2825230223130fe896ceac4e3/rindle-site/src/routes/_shell.%24slug.tsx#L43) · tantaman.github.io*

## See also

- [Preload & navigate](/docs/preloads) — the `loader`'s `query` / `ssr` / `until` options.
- [Server rendering](/docs/ssr) — what `preload` does on the server.
- [Scaffold with create-rindle](/docs/create-rindle) — a TanStack Start app with this wiring generated.

---

[View this page on Rindle](https://rindle.sh/docs/tanstack)
