Execution contract
- Use when
- Use when deciding whether route lifecycle or a separately managed Query cache should own remote data.
- Avoid when
- Do not apply this decision to local UI state; it belongs to neither loaders nor Query.
- Preconditions
- Record whether data is reused across routes and needs invalidation, polling, retries, or optimistic updates.
- Verification
- State the owner, cache policy, and refetch triggers; if combined, loader and component must share one queryOptions definition.
- Failure mode
- Duplicate requests often come from separate loader and component keys or fetchers; unify the contract before tuning staleTime.
- Security
- Both loading paths may reach private server data; authorization belongs at the data source.
Decision rule
Use a Loader when data controls route availability, redirect/notFound, or must be ready before navigation completes. Use Query for durable caching, background refetch, invalidation, retries, or optimistic updates.
Compose them
A common composition calls queryClient.ensureQueryData in the Loader: Router coordinates navigation while Query owns the cache. This requires a QueryClient in Router context.
export const Route = createFileRoute('/issues/')({
loader: ({ context }) =>
context.queryClient.ensureQueryData(issuesQueryOptions),
component: IssuesPage,
})Do not
Do not let Loader and Query fetch the same resource under unrelated keys. Do not add Query merely for uniformity when the data has no cache lifecycle needs.