From 10022b1299cc5cf9aee8428916137efed02410b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Curley?= Date: Thu, 22 Oct 2026 14:00:03 +0100 Subject: [PATCH 1/2] docs: clarify useServerFn is not needed with the router query integration --- docs/router/integrations/query.md | 2 +- docs/start/framework/react/guide/server-functions.md | 5 ++++- docs/start/framework/react/guide/tanstack-query.md | 7 ++++--- .../start-basic-react-query/src/routes/preferences.tsx | 4 +--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/router/integrations/query.md b/docs/router/integrations/query.md index 707f90900c1..bc5f647b9ad 100644 --- a/docs/router/integrations/query.md +++ b/docs/router/integrations/query.md @@ -216,7 +216,7 @@ export const Route = createFileRoute('/user/$id')({ ## Redirect handling -If a query or mutation throws a `redirect(...)`, the integration intercepts it on the client and performs a router navigation. +If a query or mutation throws a `redirect(...)`, the integration intercepts it on the client and performs a router navigation. You do not need to individually wrap [server functions](/start/latest/docs/framework/react/guide/server-functions) in `useServerFn` if they are called in a `queryFn` or `mutationFn`. - Enabled by default - Disable with `handleRedirects: false` if you need custom handling diff --git a/docs/start/framework/react/guide/server-functions.md b/docs/start/framework/react/guide/server-functions.md index 68a6b8ac72d..80742e495c8 100644 --- a/docs/start/framework/react/guide/server-functions.md +++ b/docs/start/framework/react/guide/server-functions.md @@ -93,6 +93,9 @@ function PostList() { } ``` +> [!NOTE] +> If you use the `@tanstack/react-router-ssr-query` integration package, wrapping query or mutation functions with `useServerFn` is not required. See the [integration guide](/router/latest/docs/integrations/query#redirect-handling) for more details. + ## File Organization For larger applications, consider organizing server-side code into separate files. Here's one approach: @@ -257,7 +260,7 @@ export const looseOutputServerFn = createServerFn({ ## Error Handling & Redirects -Server functions can throw errors, redirects, and not-found responses that are handled automatically when called from route lifecycles or components using `useServerFn()`. +Server functions can throw errors, redirects, and not-found responses that are handled automatically when called from route lifecycles, components using `useServerFn()`, or inside TanStack Query `queryFn` and `mutationFn` functions when the [`@tanstack/react-router-ssr-query` integration package](/router/latest/docs/integrations/query) is used. ### Basic Errors diff --git a/docs/start/framework/react/guide/tanstack-query.md b/docs/start/framework/react/guide/tanstack-query.md index 7797ae306be..3753b21b461 100644 --- a/docs/start/framework/react/guide/tanstack-query.md +++ b/docs/start/framework/react/guide/tanstack-query.md @@ -85,6 +85,8 @@ Both calls use the same query key and options. The loader populates the request' For a parameterized resource, include its identity in the key, such as `['post', postId]`. If search values affect the result, validate them and include them in both `loaderDeps` and the query key. Keep secrets out of keys and serialized query data. +Note that if you are using server functions and you have the [integration](#install-and-create-a-queryclient-per-router) installed, you do not need to use `useServerFn` to properly handle thrown errors or redirects. Simply call the server function in a `queryFn` or `mutationFn` normally. + ## Await critical data and stream secondary data Await queries that determine the page's main content, title, authorization, redirects, or whether it exists. Return title and description data from the loader when a route's `head` needs them, as the example's post route does. @@ -95,13 +97,12 @@ The example's existing `/deferred` route shows a separate Suspense boundary. See ## Invalidate Query after a server mutation -The preference example validates the display name and writes its cookie inside a POST server function. Its `src/start.ts` enables Start's CSRF middleware for server-function requests. The component calls that function through `useServerFn`, then invalidates the query that reads the cookie: +The preference example validates the display name and writes its cookie inside a POST server function. Its `src/start.ts` enables Start's CSRF middleware for server-function requests. The component calls that function, then invalidates the query that reads the cookie: ```tsx const queryClient = useQueryClient() -const save = useServerFn(saveReaderName) const mutation = useMutation({ - mutationFn: (name: string) => save({ data: name }), + mutationFn: (name: string) => saveReaderName({ data: name }), onSuccess: () => queryClient.invalidateQueries({ queryKey: readerNameOptions.queryKey }), }) diff --git a/examples/react/start-basic-react-query/src/routes/preferences.tsx b/examples/react/start-basic-react-query/src/routes/preferences.tsx index 603257fc0fd..a6ede867fe6 100644 --- a/examples/react/start-basic-react-query/src/routes/preferences.tsx +++ b/examples/react/start-basic-react-query/src/routes/preferences.tsx @@ -4,7 +4,6 @@ import { useSuspenseQuery, } from '@tanstack/react-query' import { createFileRoute, useHydrated } from '@tanstack/react-router' -import { useServerFn } from '@tanstack/react-start' import { readerNameOptions, saveReaderName } from '../utils/preferences' export const Route = createFileRoute('/preferences')({ @@ -19,10 +18,9 @@ export const Route = createFileRoute('/preferences')({ function Preferences() { const { data: name } = useSuspenseQuery(readerNameOptions) const queryClient = useQueryClient() - const save = useServerFn(saveReaderName) const hydrated = useHydrated() const mutation = useMutation({ - mutationFn: (name: string) => save({ data: name }), + mutationFn: (name: string) => saveReaderName({ data: name }), onSuccess: () => queryClient.invalidateQueries({ queryKey: readerNameOptions.queryKey }), }) From 77e3a15a5a99be199ba94f8eae4e0af3e2f9cb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciar=C3=A1n=20Curley?= Date: Thu, 22 Oct 2026 18:41:25 +0100 Subject: [PATCH 2/2] docs: clarify useServerFn wraps server functions, not query/mutation fns Co-Authored-By: Claude Opus 5.5 --- docs/start/framework/react/guide/server-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/start/framework/react/guide/server-functions.md b/docs/start/framework/react/guide/server-functions.md index 80742e495c8..ed4fa22ee85 100644 --- a/docs/start/framework/react/guide/server-functions.md +++ b/docs/start/framework/react/guide/server-functions.md @@ -94,7 +94,7 @@ function PostList() { ``` > [!NOTE] -> If you use the `@tanstack/react-router-ssr-query` integration package, wrapping query or mutation functions with `useServerFn` is not required. See the [integration guide](/router/latest/docs/integrations/query#redirect-handling) for more details. +> If you use TanStack Query with the `@tanstack/react-router-ssr-query` integration package, wrapping server functions called in `queryFn` or `mutationFn` with `useServerFn` is not required. See the [Query integration guide](/router/latest/docs/integrations/query#redirect-handling) for more details. ## File Organization