#How do I pass context to the router in TanStack Start?

20 messages · Page 1 of 1 (latest)

maiden agate
#

Hey ya'll! Quick question about TanStack Start - Is it possible to pass context to the router?

With TanStack Router, I can use RouterProvider to pass an AuthContext, for example, but in TanStack Start I have to use StartClient which doesn't give me a way to "provide" any context.

It feels like I'm missing some key understanding about how the full stack version of TanStack differs from the client-first version...

proven hinge
#

In createRouter you can add things to the router context example

if you need to pass things from react-land eg a context to the router is not possible.

Can you share more info about what you need to achieve?

GitHub

minimal TanStack Start template with React 19, Better Auth, Drizzle ORM, shadcn/ui - dotnize/react-tanstarter

vivid crag
#

Would’ve been nice to be able to inject async values in the context there.

Ex: fetch user as early as possible in middleware, pass null or user into context

vagrant lion
vivid crag
#

@vagrant lion yeah for sure! and correct me if I am wrong! the context when you invoke createTanstackRouter seems like the perfect place to do dependency injection (in this case I passed queryClient, a random string value. This is nice as it gives you the typesafety in each routes loader and serverFns ```typescript
import { QueryClient } from "@tanstack/react-query";
import { createRouter as createTanStackRouter } from "@tanstack/react-router";
import { routerWithQueryClient } from "@tanstack/react-router-with-query";
import { routeTree } from "./routeTree.gen";
import { getCloudflareCtx } from "./utils/cloudflare";

const DefaultCatchBoundary = () => <div>DefaultCatchBoundary</div>;
const DefaultNotFound = () => <div>DefaultNotFound</div>;

export const testFn = () => "testVal";

export const getUser = async () => {
//Potentially calling db?
await new Promise((res) => setTimeout(res, 200));
return { user: "randomemail@gmail.com" };
};

export function createRouter() {
const queryClient: QueryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1 * 1000,
},
},
});

return routerWithQueryClient(
createTanStackRouter({
routeTree,
defaultPreload: "intent",
context: { queryClient, testVal: testFn(), user: getUser() },
defaultErrorComponent: DefaultCatchBoundary,
defaultNotFoundComponent: DefaultNotFound,
}),
queryClient,
);
}

declare module "@tanstack/react-router" {
interface Register {
router: ReturnType<typeof createRouter>;
}
}

#

then with createRootRoute you can do with context ```typescript
export const Route = createRootRouteWithContext<{
queryClient: QueryClient;
testVal: string;
user: Promise<{
user: string;
}>;
}>()({
head: () => ({
meta: [

#

and then you get the typesafety in loader/serverFn etc ```typescript
export const Route = createFileRoute("/")({
component: Home,
loader: async ({ context, params }) => {
console.log(context.testVal);
console.log(context.user);
},
});

#

I guess the question is wanting to inject the context as early on as possible (through global middleware maybe?) before you hit the route, and run a dbCheck for the user for example and passing that in context, so now the route can access it via loaders,serverFns etc

vivid crag
#

whilst this works running it on node locally it will throw a top level await error on cloudflare.

#

Hope that makes sense, I'll be thinkering around with it more 👍

#

Looks like passing it in the rotuers context might not be a good idea anyways since it will run on the client, so no bueno

vagrant lion
#

you would need to run a different impl on the client

#

but where would it get the value from?

#

probably needs to be dehydrated on the server and hydrated on the client

vivid crag
#

yeah I'll play around with it @vagrant lion 👍 just to be clear does beforeLoad and the loader function run isomorphic?

vagrant lion
#

yes

vivid crag
#

in rr7 the loader is server only, and I think they havea new client loader