Define typed Router Context for a QueryClient, session, or service and explain its boundary with server authorization.
Declare the smallest root contract
createRootRouteWithContext makes the route tree require the same dependencies from createRouter. Put stable dependencies shared by loaders, beforeLoad, and route components here, not arbitrary component state.
import { createRootRouteWithContext } from '@tanstack/react-router'
import type { QueryClient } from '@tanstack/react-query'
type RouterContext = {
queryClient: QueryClient
session: { permissions: readonly string[] }
}
export const Route = createRootRouteWithContext<RouterContext>()({
component: RootDocument,
})Let a parent route add derived facts
The value returned by beforeLoad is merged into context for that route and its children. A parent computes canEditIssues once, so child loaders do not reinterpret permission strings and still receive complete inference.
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/_workspace')({
beforeLoad: ({ context }) => ({
canEditIssues: context.session.permissions.includes('issues:write'),
}),
})Turn this lesson into a verifiable skill
Router Context dependencies are injected at router creation and remain typed in beforeLoad and loaders.
Add QueryClient and an auth-reader interface to root context, then consume them from a protected route.
Removing a required dependency should fail router creation at typecheck; restoring it should expose the same instance to loaders.
- Calling a React hook at route-module scope.
- Using any to bypass Router Context registration.