Repository: TanStack/query (TypeScript)

Issue:
Skip fetch when `initialData` is set on `ensureQueryData`
### Describe the bug

Firstly, thank you for your work on this library! I am currently using a [pull approach](https://tkdodo.eu/blog/seeding-the-query-cache#pull-approach) to seed the query cache, and I have encountered a specific issue. When a user enters a page, I call `ensureQueryData`, passing in an `initialData` value, which may be `undefined`. The issue I am facing is that `ensureQueryData` always triggers a fetch when the data is not already in the cache, even when `initialData` is provided (non undefined).

Below is a simplified example in pseudo-code to illustrate the issue:

```typescript
  const query = queries.postById.getOptions(id);

  await queryClient.ensureQueryData({
    ...query,
    // here I search inside list queries to find an existing post to be on the initial data
    // even when I have a post, the fetch is executed
    initialData: utils.findInPages(queries.postList.getKey(), byId(id)),
  });
```

### Your minimal, reproducible example

Stackblitz

### Steps to reproduce

[https://stackblitz.com/edit/vitejs-vite-cnkcntdk?file=src%2FApp.tsx](https://stackblitz.com/edit/vitejs-vite-cnkcntdk?file=src%2FApp.tsx)

### Expected behavior

Since I am providing `initialData`, the expected behavior is for the query client to store the `initialData` in the cache and bypass the fetch process.

### How often does this bug happen?

Every time

### Screenshots or Videos

_No response_

### Platform

- OS: macOS
- Browser: Chrome 131

### Tanstack Query adapter

react-query

### TanStack Query version

5.62.3

### TypeScript version

_No response_

### Additional context

_No response_


Discussion:
good point. we need to fix that.



Patch:
diff --git a/packages/query-core/src/queryClient.ts b/packages/query-core/src/queryClient.ts
index a62a6ee9c2..72c3a42cbf 100644
--- a/packages/query-core/src/queryClient.ts
+++ b/packages/query-core/src/queryClient.ts
@@ -145,23 +145,22 @@ export class QueryClient {
   >(
     options: EnsureQueryDataOptions<TQueryFnData, TError, TData, TQueryKey>,
   ): Promise<TData> {
-    const cachedData = this.getQueryData<TData>(options.queryKey)
+    const defaultedOptions = this.defaultQueryOptions(options)
+    const query = this.#queryCache.build(this, defaultedOptions)
+    const cachedData = query.state.data
 
     if (cachedData === undefined) {
       return this.fetchQuery(options)
-    } else {
-      const defaultedOptions = this.defaultQueryOptions(options)
-      const query = this.#queryCache.build(this, defaultedOptions)
-
-      if (
-        options.revalidateIfStale &&
-        query.isStaleByTime(resolveStaleTime(defaultedOptions.staleTime, query))
-      ) {
-        void this.prefetchQuery(defaultedOptions)
-      }
+    }
 
-      return Promise.resolve(cachedData)
+    if (
+      options.revalidateIfStale &&
+      query.isStaleByTime(resolveStaleTime(defaultedOptions.staleTime, query))
+    ) {
+      void this.prefetchQuery(defaultedOptions)
     }
+
+    return Promise.resolve(cachedData)
   }
 
   getQueriesData<


Test patch:
diff --git a/packages/query-core/src/__tests__/queryClient.test.tsx b/packages/query-core/src/__tests__/queryClient.test.tsx
index ec01f5e272..11f2129db9 100644
--- a/packages/query-core/src/__tests__/queryClient.test.tsx
+++ b/packages/query-core/src/__tests__/queryClient.test.tsx
@@ -477,6 +477,21 @@ describe('queryClient', () => {
         }),
       ).resolves.toEqual('new')
     })
+
+    test('should not fetch with initialDat', async () => {
+      const key = queryKey()
+      const queryFn = vi.fn().mockImplementation(() => Promise.resolve('data'))
+
+      await expect(
+        queryClient.ensureQueryData({
+          queryKey: [key, 'id'],
+          queryFn,
+          initialData: 'initial',
+        }),
+      ).resolves.toEqual('initial')
+
+      expect(queryFn).toHaveBeenCalledTimes(0)
+    })
   })
 
   describe('ensureInfiniteQueryData', () => {