diff --git a/.changeset/config.json b/.changeset/config.json
index 5aebb25fb4b..dba75bb43e2 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -10,8 +10,11 @@
"updateInternalDependencies": "patch",
"fixed": [
[
- "@tanstack/angular-query-experimental",
- "@tanstack/angular-query-persist-client",
+ "@tanstack/angular-query",
+ "@tanstack/angular-query-devtools",
+ "@tanstack/angular-query-persist-client"
+ ],
+ [
"@tanstack/eslint-plugin-query",
"@tanstack/preact-query",
"@tanstack/preact-query-devtools",
diff --git a/.changeset/pre.json b/.changeset/pre.json
new file mode 100644
index 00000000000..3616d3a6ea5
--- /dev/null
+++ b/.changeset/pre.json
@@ -0,0 +1,4 @@
+{
+ "mode": "exit",
+ "tag": "rc"
+}
diff --git a/.changeset/pre/angular-migration-schematic.md b/.changeset/pre/angular-migration-schematic.md
new file mode 100644
index 00000000000..2a61552b1b0
--- /dev/null
+++ b/.changeset/pre/angular-migration-schematic.md
@@ -0,0 +1,5 @@
+---
+'@tanstack/angular-query': minor
+---
+
+Bundle an Angular 20.1-compatible migrate-from-experimental schematic that updates imports, migrates Angular and Nx workspace dependencies, and reports remaining API changes. Include opt-in migrations for ambiguous client references and query-core imports, with optional peer dependencies for schematic tooling.
diff --git a/.changeset/pre/angular-stable-release.md b/.changeset/pre/angular-stable-release.md
new file mode 100644
index 00000000000..175470b9f80
--- /dev/null
+++ b/.changeset/pre/angular-stable-release.md
@@ -0,0 +1,7 @@
+---
+'@tanstack/angular-query': major
+'@tanstack/angular-query-devtools': major
+'@tanstack/angular-query-persist-client': major
+---
+
+Add the stable Angular Query adapter for Angular 20.1+. It includes SSR support, experimental Resource API interoperability, persistence integration, improved internal subscription and pending tasks management, stable `injectQueries` and consistency improvements in the API.
diff --git a/docs/config.json b/docs/config.json
index 5b1a24863cb..48f41879837 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -180,20 +180,20 @@
"to": "framework/angular/quick-start"
},
{
- "label": "Angular HttpClient and other data fetching clients",
+ "label": "Devtools",
+ "to": "framework/angular/devtools"
+ },
+ {
+ "label": "Angular HttpClient",
"to": "framework/angular/angular-httpclient-and-other-data-fetching-clients"
},
{
- "label": "Devtools",
- "to": "framework/angular/devtools"
+ "label": "Resource API",
+ "to": "framework/angular/resource-api"
},
{
"label": "TypeScript",
"to": "framework/angular/typescript"
- },
- {
- "label": "Zoneless",
- "to": "framework/angular/zoneless"
}
]
},
@@ -815,6 +815,10 @@
"label": "Default Query Fn",
"to": "framework/angular/guides/default-query-function"
},
+ {
+ "label": "SSR",
+ "to": "framework/angular/guides/ssr"
+ },
{
"label": "Testing",
"to": "framework/angular/guides/testing"
@@ -822,6 +826,18 @@
{
"label": "Does this replace state managers?",
"to": "framework/angular/guides/does-this-replace-client-state"
+ },
+ {
+ "label": "Migrating from Experimental",
+ "to": "framework/angular/guides/migrating-from-experimental"
+ },
+ {
+ "label": "Migrating from ngneat/query",
+ "to": "framework/angular/guides/migrating-from-ngneat-query"
+ },
+ {
+ "label": "Error Handling",
+ "to": "framework/angular/guides/error-handling"
}
]
},
@@ -5050,12 +5066,12 @@
"to": "framework/angular/reference/functions/injectMutationState"
},
{
- "label": "Functions / injectQuery",
- "to": "framework/angular/reference/functions/injectQuery"
+ "label": "Functions / injectQueries",
+ "to": "framework/angular/reference/functions/injectQueries"
},
{
- "label": "Functions / injectQueryClient",
- "to": "framework/angular/reference/functions/injectQueryClient"
+ "label": "Functions / injectQuery",
+ "to": "framework/angular/reference/functions/injectQuery"
},
{
"label": "Functions / isCancelledError",
@@ -5085,26 +5101,10 @@
"label": "Functions / partialMatchKey",
"to": "framework/angular/reference/functions/partialMatchKey"
},
- {
- "label": "Functions / provideAngularQuery",
- "to": "framework/angular/reference/functions/provideAngularQuery"
- },
- {
- "label": "Functions / provideIsRestoring",
- "to": "framework/angular/reference/functions/provideIsRestoring"
- },
- {
- "label": "Functions / provideQueryClient",
- "to": "framework/angular/reference/functions/provideQueryClient"
- },
{
"label": "Functions / provideTanStackQuery",
"to": "framework/angular/reference/functions/provideTanStackQuery"
},
- {
- "label": "Functions / queryFeature",
- "to": "framework/angular/reference/functions/queryFeature"
- },
{
"label": "Functions / queryOptions",
"to": "framework/angular/reference/functions/queryOptions"
@@ -5117,6 +5117,18 @@
"label": "Functions / shouldThrowError",
"to": "framework/angular/reference/functions/shouldThrowError"
},
+ {
+ "label": "Functions / toResource",
+ "to": "framework/angular/reference/functions/toResource"
+ },
+ {
+ "label": "Functions / withHydrationKey",
+ "to": "framework/angular/reference/functions/withHydrationKey"
+ },
+ {
+ "label": "Functions / withNoQueryHydration",
+ "to": "framework/angular/reference/functions/withNoQueryHydration"
+ },
{
"label": "Classes / CancelledError",
"to": "framework/angular/reference/classes/CancelledError"
@@ -5157,6 +5169,10 @@
"label": "Classes / QueryObserver",
"to": "framework/angular/reference/classes/QueryObserver"
},
+ {
+ "label": "Interfaces / BaseInfiniteQueryNarrowing",
+ "to": "framework/angular/reference/interfaces/BaseInfiniteQueryNarrowing"
+ },
{
"label": "Interfaces / BaseMutationNarrowing",
"to": "framework/angular/reference/interfaces/BaseMutationNarrowing"
@@ -5169,10 +5185,6 @@
"label": "Interfaces / CancelOptions",
"to": "framework/angular/reference/interfaces/CancelOptions"
},
- {
- "label": "Interfaces / CreateBaseQueryOptions",
- "to": "framework/angular/reference/interfaces/CreateBaseQueryOptions"
- },
{
"label": "Interfaces / CreateInfiniteQueryOptions",
"to": "framework/angular/reference/interfaces/CreateInfiniteQueryOptions"
@@ -5181,14 +5193,18 @@
"label": "Interfaces / CreateMutationOptions",
"to": "framework/angular/reference/interfaces/CreateMutationOptions"
},
- {
- "label": "Interfaces / CreateQueryOptions",
- "to": "framework/angular/reference/interfaces/CreateQueryOptions"
- },
{
"label": "Interfaces / DefaultOptions",
"to": "framework/angular/reference/interfaces/DefaultOptions"
},
+ {
+ "label": "Interfaces / DefinedInfiniteQueryNarrowing",
+ "to": "framework/angular/reference/interfaces/DefinedInfiniteQueryNarrowing"
+ },
+ {
+ "label": "Interfaces / DefinedQueryNarrowing",
+ "to": "framework/angular/reference/interfaces/DefinedQueryNarrowing"
+ },
{
"label": "Interfaces / DehydrateOptions",
"to": "framework/angular/reference/interfaces/DehydrateOptions"
@@ -5266,28 +5282,8 @@
"to": "framework/angular/reference/interfaces/InitialPageParam"
},
{
- "label": "Interfaces / InjectInfiniteQueryOptions",
- "to": "framework/angular/reference/interfaces/InjectInfiniteQueryOptions"
- },
- {
- "label": "Interfaces / InjectIsFetchingOptions",
- "to": "framework/angular/reference/interfaces/InjectIsFetchingOptions"
- },
- {
- "label": "Interfaces / InjectIsMutatingOptions",
- "to": "framework/angular/reference/interfaces/InjectIsMutatingOptions"
- },
- {
- "label": "Interfaces / InjectMutationOptions",
- "to": "framework/angular/reference/interfaces/InjectMutationOptions"
- },
- {
- "label": "Interfaces / InjectMutationStateOptions",
- "to": "framework/angular/reference/interfaces/InjectMutationStateOptions"
- },
- {
- "label": "Interfaces / InjectQueryOptions",
- "to": "framework/angular/reference/interfaces/InjectQueryOptions"
+ "label": "Interfaces / InjectQueriesOptions",
+ "to": "framework/angular/reference/interfaces/InjectQueriesOptions"
},
{
"label": "Interfaces / InvalidateOptions",
@@ -5409,6 +5405,10 @@
"label": "Interfaces / QueryOptions",
"to": "framework/angular/reference/interfaces/QueryOptions"
},
+ {
+ "label": "Interfaces / QueryResource",
+ "to": "framework/angular/reference/interfaces/QueryResource"
+ },
{
"label": "Interfaces / QueryState",
"to": "framework/angular/reference/interfaces/QueryState"
@@ -5469,6 +5469,10 @@
"label": "Types / CreateMutationResult",
"to": "framework/angular/reference/type-aliases/CreateMutationResult"
},
+ {
+ "label": "Types / CreateQueryOptions",
+ "to": "framework/angular/reference/type-aliases/CreateQueryOptions"
+ },
{
"label": "Types / CreateQueryResult",
"to": "framework/angular/reference/type-aliases/CreateQueryResult"
@@ -5513,10 +5517,6 @@
"label": "Types / DefinedQueryObserverResult",
"to": "framework/angular/reference/type-aliases/DefinedQueryObserverResult"
},
- {
- "label": "Types / DevtoolsFeature",
- "to": "framework/angular/reference/type-aliases/DevtoolsFeature"
- },
{
"label": "Types / DistributiveOmit",
"to": "framework/angular/reference/type-aliases/DistributiveOmit"
@@ -5601,6 +5601,10 @@
"label": "Types / MutationScope",
"to": "framework/angular/reference/type-aliases/MutationScope"
},
+ {
+ "label": "Types / MutationStateOptions",
+ "to": "framework/angular/reference/type-aliases/MutationStateOptions"
+ },
{
"label": "Types / MutationStatus",
"to": "framework/angular/reference/type-aliases/MutationStatus"
@@ -5629,10 +5633,6 @@
"label": "Types / Override",
"to": "framework/angular/reference/type-aliases/Override"
},
- {
- "label": "Types / PersistQueryClientFeature",
- "to": "framework/angular/reference/type-aliases/PersistQueryClientFeature"
- },
{
"label": "Types / PlaceholderDataFunction",
"to": "framework/angular/reference/type-aliases/PlaceholderDataFunction"
@@ -5657,10 +5657,6 @@
"label": "Types / QueryCacheNotifyEvent",
"to": "framework/angular/reference/type-aliases/QueryCacheNotifyEvent"
},
- {
- "label": "Types / QueryFeatures",
- "to": "framework/angular/reference/type-aliases/QueryFeatures"
- },
{
"label": "Types / QueryFunction",
"to": "framework/angular/reference/type-aliases/QueryFunction"
@@ -7258,6 +7254,30 @@
{
"label": "Devtools embedded panel (Angular Router)",
"to": "framework/angular/examples/devtools-panel-angular-router"
+ },
+ {
+ "label": "Dynamic devtools",
+ "to": "framework/angular/examples/dynamic-devtools"
+ },
+ {
+ "label": "Dynamic queries",
+ "to": "framework/angular/examples/dynamic-queries"
+ },
+ {
+ "label": "Persister",
+ "to": "framework/angular/examples/basic-persister"
+ },
+ {
+ "label": "SSR",
+ "to": "framework/angular/examples/ssr"
+ },
+ {
+ "label": "SSR with persistence",
+ "to": "framework/angular/examples/ssr-persist"
+ },
+ {
+ "label": "toResource with Signal Forms",
+ "to": "framework/angular/examples/to-resource-signal-forms"
}
]
},
@@ -7411,6 +7431,15 @@
}
]
},
+ {
+ "label": "angular",
+ "children": [
+ {
+ "label": "persistQueryClient",
+ "to": "framework/angular/plugins/persistQueryClient"
+ }
+ ]
+ },
{
"label": "preact",
"children": [
diff --git a/docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md b/docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md
index bf075980046..5319e109ccc 100644
--- a/docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md
+++ b/docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md
@@ -1,24 +1,18 @@
---
id: Angular-HttpClient-and-other-data-fetching-clients
-title: Angular HttpClient and other data fetching clients
+title: Angular HttpClient
---
-Because TanStack Query's fetching mechanisms are agnostically built on Promises, you can use literally any asynchronous data fetching client, including the browser native `fetch` API, `graphql-request`, and more.
+TanStack Query works with any data fetching client that returns a Promise, including the browser's
+`fetch` API and clients such as `graphql-request`.
## Using Angular's `HttpClient` for data fetching
-`HttpClient` is a powerful and integrated part of Angular, which gives the following benefits:
+Angular's `HttpClient` returns Observables, which query and mutation functions do not consume
+directly. Convert the Observable with RxJS's `firstValueFrom` or `lastValueFrom`. Query functions
+can also return a synchronous value.
-- Mock responses in unit tests using [provideHttpClientTesting](https://angular.dev/guide/http/testing).
-- [Interceptors](https://angular.dev/guide/http/interceptors) can be used for a wide range of functionality including adding authentication headers, performing logging, etc. While some data fetching libraries have their own interceptor system, `HttpClient` interceptors are integrated with Angular's dependency injection system.
-- `HttpClient` automatically informs [`PendingTasks`](https://angular.dev/api/core/PendingTasks#), which enables Angular to be aware of pending requests. Unit tests and SSR can use the resulting application _stableness_ information to wait for pending requests to finish. This makes unit testing much easier for [Zoneless](https://angular.dev/guide/zoneless) applications.
-- When using SSR, `HttpClient` will [cache requests](https://angular.dev/guide/ssr#caching-data-when-using-HttpClient) performed on the server. This will prevent unneeded requests on the client. `HttpClient` SSR caching works out of the box. TanStack Query has its own hydration functionality which may be more powerful but requires some setup. Which one fits your needs best depends on your use case.
-
-### Using observables in `queryFn`
-
-As TanStack Query is a promise based library, observables from `HttpClient` need to be converted to promises. This can be done with the `lastValueFrom` or `firstValueFrom` functions from `rxjs`.
-
-```angular-ts
+```ts
@Component({
// ...
})
@@ -28,21 +22,28 @@ class ExampleComponent {
readonly repoDataQuery = injectQuery(() => ({
queryKey: ['repoData'],
queryFn: () =>
- lastValueFrom(
+ firstValueFrom(
this.http.get('https://api.github.com/repos/TanStack/query'),
),
}))
}
```
-> Since Angular is moving towards RxJS as an optional dependency, it's expected that `HttpClient` will also support promises in the future.
->
-> Support for observables in TanStack Query for Angular is planned.
+For regular `HttpClient` requests, `firstValueFrom` resolves the single response and unsubscribes.
+Use `lastValueFrom` when the Observable emits multiple values and the query should resolve with the
+last one.
+
+Angular [HTTP interceptors](https://angular.dev/guide/http/interceptors) continue to apply to
+requests made inside query and mutation functions.
+
+## SSR
+
+When using `HttpClient` with SSR, prefer Angular Query's built-in query hydration and disable
+Angular's HTTP transfer cache. Otherwise, both systems serialize the same request data.
-## Comparison table
+Add
+[`withNoHttpTransferCache()`](https://angular.dev/api/platform-browser/withNoHttpTransferCache) to
+[`provideClientHydration()`](https://angular.dev/api/platform-browser/provideClientHydration). See
+the [SSR guide](./guides/ssr.md) for the complete setup.
-| Data fetching client | Pros | Cons |
-| --------------------------------------------------- | --------------------------------------------------- | -------------------------------------------------------------------------- |
-| **Angular HttpClient** | Featureful and very well integrated with Angular. | Observables need to be converted to Promises. |
-| **Fetch** | Browser native API, so adds nothing to bundle size. | Barebones API which lacks many features. |
-| **Specialized libraries such as `graphql-request`** | Specialized features for specific use cases. | If it's not an Angular library it won't integrate well with the framework. |
+For cancellation, see [Query Cancellation](./guides/query-cancellation.md).
diff --git a/docs/framework/angular/devtools.md b/docs/framework/angular/devtools.md
index 54afa93ed30..62adad473b5 100644
--- a/docs/framework/angular/devtools.md
+++ b/docs/framework/angular/devtools.md
@@ -11,79 +11,129 @@ title: Devtools
## Enable devtools
+Add the devtools package (in addition to `@tanstack/angular-query`):
+
+```sh
+npm install @tanstack/angular-query-devtools
+```
+
The devtools help you debug and inspect your queries and mutations. You can enable the devtools by adding `withDevtools` to `provideTanStackQuery`.
-By default, Angular Query Devtools are only included in development mode bundles, so you don't need to worry about excluding them during a production build.
+By default, Angular Query Devtools only load in development.
```ts
-import {
- QueryClient,
- provideTanStackQuery,
-} from '@tanstack/angular-query-experimental'
+import { QueryClient, provideTanStackQuery } from '@tanstack/angular-query'
-import { withDevtools } from '@tanstack/angular-query-experimental/devtools'
+import { withDevtools } from '@tanstack/angular-query-devtools'
export const appConfig: ApplicationConfig = {
- providers: [provideTanStackQuery(new QueryClient(), withDevtools())],
+ providers: [provideTanStackQuery(() => new QueryClient(), withDevtools())],
}
```
## Devtools in production
-Devtools are automatically excluded from production builds. However, it might be desirable to lazy load the devtools in production.
-
-To use `withDevtools` in production builds, import using the `production` sub-path. The function exported from the production subpath is identical to the main one, but won't be excluded from production builds.
+If you need the real implementation in production, import from the `production` entrypoint.
```ts
-import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
+import { withDevtools } from '@tanstack/angular-query-devtools/production'
```
-To control when devtools are loaded, you can use the `loadDevtools` option.
+To control when devtools are rendered, use the `loadDevtools` option.
-When not setting the option or setting it to 'auto', the devtools will be loaded automatically only when Angular runs in development mode.
+When omitted or set to `'auto'`, devtools are only rendered in development mode.
```ts
-import { withDevtools } from '@tanstack/angular-query-experimental/devtools'
+import { withDevtools } from '@tanstack/angular-query-devtools'
-provideTanStackQuery(new QueryClient(), withDevtools())
+providers: [provideTanStackQuery(() => new QueryClient(), withDevtools())]
// which is equivalent to
-provideTanStackQuery(
- new QueryClient(),
- withDevtools(() => ({ loadDevtools: 'auto' })),
-)
+providers: [
+ provideTanStackQuery(
+ () => new QueryClient(),
+ withDevtools(() => ({ loadDevtools: 'auto' })),
+ ),
+]
```
-When setting the option to true, the devtools will be loaded in both development and production mode.
+When setting the option to true, the devtools will be rendered in both development and production mode.
This is useful if you want to load devtools based on [Angular environment configurations](https://angular.dev/tools/cli/environments). E.g. you could set this to true when the application is running on your production build staging environment.
```ts
import { environment } from './environments/environment'
// Make sure to use the production sub-path to load devtools in production builds
-import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
+import { withDevtools } from '@tanstack/angular-query-devtools/production'
+
+providers: [
+ provideTanStackQuery(
+ () => new QueryClient(),
+ withDevtools(() => ({ loadDevtools: environment.loadDevtools })),
+ ),
+]
+```
+
+When setting the option to false, the devtools will not be rendered.
+
+```ts
+providers: [
+ provideTanStackQuery(
+ () => new QueryClient(),
+ withDevtools(() => ({ loadDevtools: false })),
+ ),
+]
+```
+
+### Webpack file replacements
+
+Some webpack-based Angular builders do not apply package export conditions when
+they bundle application code. Use the explicit `production` and `stub`
+entrypoints with Angular CLI file replacements to keep the devtools dependency
+out of production bundles.
+
+Create an application-level import that can be replaced:
+
+```ts
+// src/app/query-devtools.ts
+export { withDevtools } from '@tanstack/angular-query-devtools/production'
+```
-provideTanStackQuery(
- new QueryClient(),
- withDevtools(() => ({ loadDevtools: environment.loadDevtools })),
-)
+```ts
+// src/app/query-devtools.stub.ts
+export { withDevtools } from '@tanstack/angular-query-devtools/stub'
```
-When setting the option to false, the devtools will not be loaded.
+Import the application-level module from your config:
```ts
-provideTanStackQuery(
- new QueryClient(),
- withDevtools(() => ({ loadDevtools: false })),
-)
+import { withDevtools } from './query-devtools'
+```
+
+Then configure the production build:
+
+```json
+{
+ "configurations": {
+ "production": {
+ "fileReplacements": [
+ {
+ "replace": "src/app/query-devtools.ts",
+ "with": "src/app/query-devtools.stub.ts"
+ }
+ ]
+ }
+ }
+}
```
-## Derive options through reactivity
+The same pattern is available for the [embedded panel](#embedded-mode):
+`@tanstack/angular-query-devtools/devtools-panel/production` and
+`@tanstack/angular-query-devtools/devtools-panel/stub`.
-Options are passed to `withDevtools` from a callback function to support reactivity through signals. In the following example
-a signal is created from a RxJS observable that emits on a keyboard shortcut. When the derived signal is set to true, the devtools are lazily loaded.
+## Reactive options
-The example below always loads devtools in development mode and loads on-demand in production mode when a keyboard shortcut is pressed.
+Mutable options can be Angular signals. For example, a signal derived from a keyboard shortcut can show devtools on demand:
```ts
import { Injectable, isDevMode } from '@angular/core'
@@ -107,29 +157,23 @@ export class DevtoolsOptionsManager {
}
```
-If you want to use an injectable such as a service in the callback you can use `deps`. The injected value will be passed as parameter to the callback function.
-
-This is similar to `deps` in Angular's [`useFactory`](https://angular.dev/guide/di/dependency-injection-providers#factory-providers-usefactory) provider.
+The callback runs once in an Angular injection context, so it can call
+`inject()`. Return signals as option values to update them reactively:
```ts
// ...
-// 👇 Note we import from the production sub-path to enable devtools lazy loading in production builds
-import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
+// 👇 Import from the production sub-path to make devtools available in production builds
+import { inject } from '@angular/core'
+import { withDevtools } from '@tanstack/angular-query-devtools/production'
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideTanStackQuery(
- new QueryClient(),
- withDevtools(
- (devToolsOptionsManager: DevtoolsOptionsManager) => ({
- loadDevtools: devToolsOptionsManager.loadDevtools(),
- }),
- {
- // `deps` is used to inject and pass `DevtoolsOptionsManager` to the `withDevtools` callback.
- deps: [DevtoolsOptionsManager],
- },
- ),
+ () => new QueryClient(),
+ withDevtools(() => ({
+ loadDevtools: inject(DevtoolsOptionsManager).loadDevtools,
+ })),
),
],
}
@@ -137,11 +181,16 @@ export const appConfig: ApplicationConfig = {
### Options returned from the callback
-Of these options `loadDevtools`, `client`, `position`, `errorTypes`, `buttonPosition`, `initialIsOpen`, and `theme` support reactivity through signals.
+`loadDevtools`, `client`, `position`, `errorTypes`, `buttonPosition`,
+`initialIsOpen`, and `theme` accept either their documented static value or a
+signal containing that value.
+
+`styleNonce`, `shadowDOMTarget`, and `hideDisabledQueries` are construction-time
+options and do not accept signals.
- `loadDevtools?: 'auto' | boolean`
- - Defaults to `auto`: lazily loads devtools when in development mode. Skips loading in production mode.
- - Use this to control if the devtools are loaded.
+ - Omit or `'auto'`: load devtools only in development mode.
+ - Use this to control whether devtools load when using the `/production` import.
- `initialIsOpen?: Boolean`
- Set this to `true` if you want the tools to default to being open
- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "relative"`
@@ -165,17 +214,17 @@ Of these options `loadDevtools`, `client`, `position`, `errorTypes`, `buttonPosi
- Set this to true to hide disabled queries from the devtools panel.
- `theme?: "light" | "dark" | "system"`
- Defaults to the theme selected in the devtools Settings menu, or `system` if none is selected.
- - Set this to change the theme of the devtools panel. This overrides the theme selected in the Settings menu.
+ - Sets the theme of the devtools panel, overriding the Settings menu selection.
## Embedded Mode
Embedded mode will show the development tools as a fixed element in your application, so you can use our panel in your own development tools.
-Use `injectDevtoolsPanel` to render the devtools panel inside an element of your component. Like `withDevtools`, it is only included in development mode bundles. To use it in production builds, import it from `@tanstack/angular-query-experimental/devtools-panel/production`.
+Use `injectDevtoolsPanel` to render the devtools panel inside an element of your component. Like `withDevtools`, it is only included in development mode bundles. To use it in production builds, import it from `@tanstack/angular-query-devtools/devtools-panel/production`.
```angular-ts
import { Component, signal, viewChild } from '@angular/core'
-import { injectDevtoolsPanel } from '@tanstack/angular-query-experimental/devtools-panel'
+import { injectDevtoolsPanel } from '@tanstack/angular-query-devtools/devtools-panel'
import type { ElementRef } from '@angular/core'
@Component({
@@ -200,15 +249,20 @@ export class AppComponent {
}
```
-`injectDevtoolsPanel` must be called in an injection context, or be given an `Injector` through the `injector` option in its second argument: `injectDevtoolsPanel(() => ({ ... }), { injector })`.
+`injectDevtoolsPanel` must be called in an injection context. To create the panel later, for example after lazy loading the entry point, wrap the call in [`runInInjectionContext`](https://angular.dev/api/core/runInInjectionContext). It returns a `DevtoolsPanelRef`; call its `destroy()` to remove the panel before the injector that created it is destroyed.
+
+See the [devtools panel example](./examples/devtools-panel-angular-router) for both variants.
### Options
-Of these options `hostElement`, `client`, `errorTypes`, `onClose`, and `theme` support reactivity through signals.
+The callback is reactive: `hostElement`, `client`, `errorTypes`, `onClose`, and `theme` are applied whenever a signal read in the callback changes.
+
+`styleNonce`, `shadowDOMTarget`, and `hideDisabledQueries` are construction-time
+options, read when the panel is created.
-- `hostElement?: ElementRef`
+- `hostElement?: ElementRef | null`
- The element to render the devtools panel in. When it is `undefined` or `null`, the devtools panel is not created, or is destroyed if it exists.
-- `onClose?: () => void`
+- `onClose?: () => unknown`
- Callback function that is called when the devtools panel is closed
- `client?: QueryClient`,
- Use this to use a custom QueryClient. Otherwise, the QueryClient provided through `provideTanStackQuery` will be injected.
@@ -224,7 +278,7 @@ Of these options `hostElement`, `client`, `errorTypes`, `onClose`, and `theme` s
- Set this to true to hide disabled queries from the devtools panel.
- `theme?: "light" | "dark" | "system"`
- Defaults to the theme selected in the devtools Settings menu, or `system` if none is selected.
- - Set this to change the theme of the devtools panel. This overrides the theme selected in the Settings menu.
+ - Sets the theme of the devtools panel, overriding the Settings menu selection.
## Filter queries and mutations
diff --git a/docs/framework/angular/guides/background-fetching-indicators.md b/docs/framework/angular/guides/background-fetching-indicators.md
index 9e5c5804383..032ffae833b 100644
--- a/docs/framework/angular/guides/background-fetching-indicators.md
+++ b/docs/framework/angular/guides/background-fetching-indicators.md
@@ -6,7 +6,7 @@ replace:
{
'useIsFetching': 'injectIsFetching',
'hook': 'function',
- '@tanstack/react-query': '@tanstack/angular-query-experimental',
+ '@tanstack/react-query': '@tanstack/angular-query',
}
---
@@ -42,7 +42,7 @@ class TodosComponent {
[//]: # 'Example2'
```angular-ts
-import { injectIsFetching } from '@tanstack/angular-query-experimental'
+import { injectIsFetching } from '@tanstack/angular-query'
@Component({
selector: 'global-loading-indicator',
@@ -58,3 +58,14 @@ export class GlobalLoadingIndicatorComponent {
```
[//]: # 'Example2'
+
+## Reactive filters
+
+Pass a factory when filtering activity. It can read signals or required component inputs:
+
+```ts
+readonly isFetching = injectIsFetching(() => ({ queryKey: ['todos', this.userId()] }))
+readonly isMutating = injectIsMutating(() => ({ mutationKey: ['save', this.userId()] }))
+```
+
+The count updates when these dependencies change.
diff --git a/docs/framework/angular/guides/default-query-function.md b/docs/framework/angular/guides/default-query-function.md
index a7ba445b318..9227eed2817 100644
--- a/docs/framework/angular/guides/default-query-function.md
+++ b/docs/framework/angular/guides/default-query-function.md
@@ -16,16 +16,17 @@ const defaultQueryFn: QueryFunction = async ({ queryKey }) => {
}
// provide the default query function to your app with defaultOptions
-const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- queryFn: defaultQueryFn,
+const createQueryClient = () =>
+ new QueryClient({
+ defaultOptions: {
+ queries: {
+ queryFn: defaultQueryFn,
+ },
},
- },
-})
+ })
bootstrapApplication(MyAppComponent, {
- providers: [provideTanStackQuery(queryClient)],
+ providers: [provideTanStackQuery(createQueryClient)],
})
export class PostsComponent {
diff --git a/docs/framework/angular/guides/dependent-queries.md b/docs/framework/angular/guides/dependent-queries.md
index 38afbd491f7..a1a58286120 100644
--- a/docs/framework/angular/guides/dependent-queries.md
+++ b/docs/framework/angular/guides/dependent-queries.md
@@ -27,7 +27,13 @@ projectsQuery = injectQuery(() => ({
[//]: # 'Example2'
```ts
-// injectQueries is under development for Angular Query
+projectsQueries = injectQueries(() => ({
+ queries:
+ this.userQuery.data()?.projectIds.map((projectId) => ({
+ queryKey: ['project', projectId],
+ queryFn: () => getProjectById(projectId),
+ })) ?? [],
+}))
```
[//]: # 'Example2'
diff --git a/docs/framework/angular/guides/disabling-queries.md b/docs/framework/angular/guides/disabling-queries.md
index b52266505aa..07bacf2d914 100644
--- a/docs/framework/angular/guides/disabling-queries.md
+++ b/docs/framework/angular/guides/disabling-queries.md
@@ -70,7 +70,7 @@ export class TodosComponent {
[//]: # 'Example3'
```angular-ts
-import { skipToken, injectQuery } from '@tanstack/angular-query-experimental'
+import { skipToken, injectQuery } from '@tanstack/angular-query'
@Component({
selector: 'todos',
diff --git a/docs/framework/angular/guides/does-this-replace-client-state.md b/docs/framework/angular/guides/does-this-replace-client-state.md
index 3872115c940..c1118ff4b28 100644
--- a/docs/framework/angular/guides/does-this-replace-client-state.md
+++ b/docs/framework/angular/guides/does-this-replace-client-state.md
@@ -4,8 +4,10 @@ title: Does TanStack Query replace global state managers?
ref: docs/framework/react/guides/does-this-replace-client-state.md
replace:
{
- 'useQuery': 'injectQuery',
- 'useMutation': 'injectMutation',
+ 'Does TanStack Query replace Redux, MobX or other global state managers\?': 'Does TanStack Query replace global state managers?',
+ 'Redux, MobX, Zustand, etc.': 'NgRx Store, Signal Store, etc.',
+ '`useQuery`': '`injectQuery`',
+ '`useMutation`': '`injectMutation`',
'hook': 'function',
}
---
diff --git a/docs/framework/angular/guides/error-handling.md b/docs/framework/angular/guides/error-handling.md
new file mode 100644
index 00000000000..4efdfcf87ef
--- /dev/null
+++ b/docs/framework/angular/guides/error-handling.md
@@ -0,0 +1,57 @@
+---
+id: error-handling
+title: Error Handling
+---
+
+Query and mutation errors are exposed through their result signals. The adapter does not report
+failed requests to a global error handler automatically.
+
+To report cache failures to Angular's `ErrorHandler`, configure the cache callbacks when creating
+the client. Capture the handler in the provider factory, where `inject()` is available:
+
+```ts
+import { ErrorHandler, inject } from '@angular/core'
+import {
+ MutationCache,
+ QueryCache,
+ QueryClient,
+ provideTanStackQuery,
+} from '@tanstack/angular-query'
+
+export const queryProviders = provideTanStackQuery(() => {
+ const errors = inject(ErrorHandler)
+
+ return new QueryClient({
+ queryCache: new QueryCache({
+ onError: (error, query) => {
+ if (query.meta?.reportToErrorHandler !== false) {
+ errors.handleError(error)
+ }
+ },
+ }),
+ mutationCache: new MutationCache({
+ onError: (error, _variables, _context, mutation) => {
+ if (mutation.meta?.reportToErrorHandler !== false) {
+ errors.handleError(error)
+ }
+ },
+ }),
+ })
+})
+```
+
+This example reports failures by default. Set `meta: { reportToErrorHandler: false }` on a query or
+mutation which your application handles locally. Compose these callbacks with any cache callbacks
+you already use.
+
+A query cache callback reports a failed cache operation once, even when several components observe
+the query. Observer-only `select` errors and exceptions in options or `combine` computations are
+not cache failures and are not reported by this recipe.
+
+`mutateAsync()` rejects and can be caught with `try`/`catch`. `mutate()` returns void; use mutation
+callbacks or result signals for its error state. `refetch({ throwOnError: true })` opts into promise
+rejection for that call.
+
+The [Resource view](../resource-api.md) throws from `value()` when its mapped status is `error`.
+Check `hasValue()` before reading it. An uncaught error while Angular renders a template can still
+reach Angular's error handler. This integration does not provide a component error boundary.
diff --git a/docs/framework/angular/guides/important-defaults.md b/docs/framework/angular/guides/important-defaults.md
index 886792038b1..95a6b1df98a 100644
--- a/docs/framework/angular/guides/important-defaults.md
+++ b/docs/framework/angular/guides/important-defaults.md
@@ -6,6 +6,7 @@ replace:
{
'React': 'Angular',
'react-query': 'angular-query',
+ '@tanstack/angular-query': '@tanstack/angular-query',
'useQuery': 'injectQuery',
'useInfiniteQuery': 'injectInfiniteQuery',
'useMemo and useCallback': 'setting signal values',
diff --git a/docs/framework/angular/guides/infinite-queries.md b/docs/framework/angular/guides/infinite-queries.md
index 27a077a048b..b912fb41470 100644
--- a/docs/framework/angular/guides/infinite-queries.md
+++ b/docs/framework/angular/guides/infinite-queries.md
@@ -10,7 +10,7 @@ replace:
```angular-ts
import { Component, computed, inject } from '@angular/core'
-import { injectInfiniteQuery } from '@tanstack/angular-query-experimental'
+import { injectInfiniteQuery } from '@tanstack/angular-query'
import { lastValueFrom } from 'rxjs'
import { ProjectsService } from './projects-service'
diff --git a/docs/framework/angular/guides/invalidations-from-mutations.md b/docs/framework/angular/guides/invalidations-from-mutations.md
index e69c4e5be7c..dc92e619311 100644
--- a/docs/framework/angular/guides/invalidations-from-mutations.md
+++ b/docs/framework/angular/guides/invalidations-from-mutations.md
@@ -17,10 +17,7 @@ postTodoMutation = injectMutation(() => ({
[//]: # 'Example2'
```ts
-import {
- injectMutation,
- QueryClient,
-} from '@tanstack/angular-query-experimental'
+import { injectMutation, QueryClient } from '@tanstack/angular-query'
export class TodosComponent {
readonly queryClient = inject(QueryClient)
diff --git a/docs/framework/angular/guides/migrating-from-experimental.md b/docs/framework/angular/guides/migrating-from-experimental.md
new file mode 100644
index 00000000000..2c0b7181a3b
--- /dev/null
+++ b/docs/framework/angular/guides/migrating-from-experimental.md
@@ -0,0 +1,373 @@
+---
+id: migrating-from-experimental
+title: Migrating from Angular Query Experimental
+---
+
+The stable package keeps the callback-based query, mutation, and signal result APIs from the
+experimental adapter. Most application queries therefore only need an import change. The following
+sections cover the breaking configuration and entrypoint changes.
+
+Angular 20.1 or newer is required by the stable package. Upgrade Angular first if your
+application is on an older version. Save your work and confirm the application builds before
+running the migration.
+
+## Active codebase recommendations
+
+Before migrating an active codebase, it is recommended that you:
+
+- Block imports of the removed `provideQueryClient` in favor of `provideTanStackQuery`.
+- Create a `provideTestTanStackQuery` helper or a `createTestQueryClient` factory to pass to `provideTanStackQuery`, so new tests use a shared provider setup.
+
+Use ESLint's [`no-restricted-imports`](https://eslint.org/docs/latest/rules/no-restricted-imports)
+to restrict experimental package imports while new code adopts `@tanstack/angular-query`.
+Suppress existing imports with [ESLint suppressions](https://eslint.org/docs/latest/use/suppressions)
+or a [rule-specific disable comment](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1),
+and remove each suppression as its import is migrated.
+
+For a gradual import migration, a package-manager alias can let new imports use the experimental
+adapter before you switch packages. For example, with pnpm:
+
+```json
+{
+ "dependencies": {
+ "@tanstack/angular-query": "npm:@tanstack/angular-query-experimental@5.90.25",
+ "@tanstack/angular-query-experimental": "5.90.25"
+ }
+}
+```
+
+Keep both names on the same resolved version and peer dependency configuration, and verify they
+resolve to the same adapter instance. The alias still exposes the experimental API; it does not
+make the stable provider signatures available. Leave devtools and `inject-queries-experimental`
+imports on their original experimental paths until the package switch so the schematic can
+recognize them. Replace the alias with the real stable package before running the schematic.
+
+## Run the migration schematic
+
+Install the stable package, then preview the bundled migration:
+
+```sh
+npm install @tanstack/angular-query
+
+# With the Angular CLI
+ng generate @tanstack/angular-query:migrate-from-experimental --dry-run
+ng generate @tanstack/angular-query:migrate-from-experimental
+
+# With Nx
+nx g @tanstack/angular-query:migrate-from-experimental --skipInstall
+```
+
+With `--skipInstall`, run your package manager's install command after applying the migration
+to synchronize the dependencies and lockfile.
+
+The schematic handles common migration steps like updating package and devtools imports,
+updating dependencies, renaming providers, and converting direct `new QueryClient()` provider
+arguments to factories. Review its warnings and the remaining sections for changes that require
+manual updates.
+
+Two additional migrations are opt-in:
+
+- `--unsafe-wrap-client-references` wraps references such as `provideTanStackQuery(client)`
+ in a factory. Review every warning: injection tokens and existing factories need different handling.
+- `--migrate-query-core-imports` moves `@tanstack/query-core` imports to `@tanstack/angular-query`
+ and removes direct core dependencies. Dependencies are kept when unmigrated references remain.
+
+The schematic also discovers `project.json` and `package.json` `nx` configurations.
+It checks project-local `tsconfig.spec.json` and `tsconfig.test.json` for manually configured
+test runners, unless a test target supplies an explicit `tsConfig`. Configured includes and
+exclusions determine which files are migrated. Projects configured entirely through inferred
+plugin settings may need manual review.
+
+## Replace the experimental package
+
+```sh
+npm uninstall @tanstack/angular-query-experimental
+npm install @tanstack/angular-query
+```
+
+```ts
+import { injectQuery } from '@tanstack/angular-query-experimental' // [!code --]
+import { injectQuery } from '@tanstack/angular-query' // [!code ++]
+```
+
+## Provide a client factory
+
+`provideTanStackQuery` no longer accepts a pre-created `QueryClient`. Pass a factory instead.
+
+```ts
+provideTanStackQuery(new QueryClient()) // [!code --]
+provideTanStackQuery(() => new QueryClient()) // [!code ++]
+```
+
+`provideTanStackQuery` now returns one `EnvironmentProviders` value rather than an array. Use it in
+an environment injector, such as `ApplicationConfig.providers`, the `providers` passed to
+`bootstrapApplication`, route-level `Route.providers`, or `createEnvironmentInjector`. It is not
+supported in `@Component.providers` or `@Directive.providers`. Add the result directly; do not
+spread it.
+
+```ts
+providers: [...provideTanStackQuery(() => new QueryClient())] // [!code --]
+providers: [provideTanStackQuery(() => new QueryClient())] // [!code ++]
+```
+
+If another provider already owns the client, resolve it inside the factory:
+
+```ts
+provideTanStackQuery(() => inject(MY_QUERY_CLIENT))
+```
+
+Replace direct token arguments with this form.
+
+`provideAngularQuery` and `provideQueryClient` have been removed. Use `provideTanStackQuery`,
+which handles mounting, unmounting, and default hydration. Replacing it with a bare Angular
+`useFactory` provider would omit that setup.
+
+```ts
+provideAngularQuery(new QueryClient()) // [!code --]
+provideTanStackQuery(() => new QueryClient()) // [!code ++]
+```
+
+For `provideQueryClient`, rename it to `provideTanStackQuery` and keep the existing client factory.
+
+## Replace `injectQueryClient`
+
+`injectQueryClient` has been removed. Inject `QueryClient` directly instead:
+
+```ts
+const queryClient = injectQueryClient() // [!code --]
+const queryClient = inject(QueryClient) // [!code ++]
+```
+
+## Install the standalone devtools package
+
+Devtools no longer ship as entrypoints of the core Angular package.
+
+```sh
+npm install @tanstack/angular-query-devtools
+```
+
+```ts
+import { withDevtools } from '@tanstack/angular-query-experimental/devtools' // [!code --]
+import { withDevtools } from '@tanstack/angular-query-devtools' // [!code ++]
+```
+
+The production and panel entrypoints move in the same way:
+
+```ts
+import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production' // [!code --]
+import { withDevtools } from '@tanstack/angular-query-devtools/production' // [!code ++]
+```
+
+The devtools options callback now runs in an injection context. Remove the `deps` option and call
+`inject()` inside the callback instead.
+
+```ts
+const optionsFromManager = (manager: DevtoolsOptionsManager) => ({
+ loadDevtools: manager.loadDevtools,
+})
+
+withDevtools(optionsFromManager, { deps: [DevtoolsOptionsManager] }) // [!code --]
+withDevtools(() => optionsFromManager(inject(DevtoolsOptionsManager))) // [!code ++]
+```
+
+See the [Devtools guide](../devtools.md) for setup, production entrypoints, and configuration
+options.
+
+## Use the stable `injectQueries` export
+
+`injectQueries` is now exported from the main package. The helper must be called from an Angular
+injection context.
+
+```ts
+import {
+ injectQueries, // [!code --]
+} from '@tanstack/angular-query-experimental/inject-queries-experimental' // [!code --]
+import { injectQueries } from '@tanstack/angular-query' // [!code ++]
+
+const getQueries = () => ({ queries })
+const results = injectQueries(getQueries, injector) // [!code --]
+const results = runInInjectionContext(injector, () => injectQueries(getQueries)) // [!code ++]
+```
+
+The `queries` callback is reactive, tuple inference is preserved, and `combine` can derive a single
+result:
+
+```ts
+readonly summary = injectQueries(() => ({
+ queries: [todosOptions(), usersOptions()],
+ combine: ([todos, users]) => ({
+ pending: todos.isPending || users.isPending,
+ todoCount: todos.data?.length ?? 0,
+ userCount: users.data?.length ?? 0,
+ }),
+}))
+```
+
+## Move explicit injectors into an injection context
+
+All stable injection helpers must run in an Angular injection context. The
+experimental `injectQuery`, `injectInfiniteQuery`, `injectMutation`,
+`injectMutationState`, `injectIsFetching`, and `injectIsMutating` accepted a second
+`{ injector }` options argument. `injectIsRestoring` accepted that options object
+as its first argument. The experimental `injectDevtoolsPanel` also accepted a second
+`{ injector }` options argument. These arguments have been removed.
+
+```ts
+injectQuery(options, { injector }) // [!code --]
+runInInjectionContext(injector, () => injectQuery(options)) // [!code ++]
+
+injectMutation(options, { injector }) // [!code --]
+runInInjectionContext(injector, () => injectMutation(options)) // [!code ++]
+
+injectIsFetching({ queryKey: ['todos'] }, { injector }) // [!code --]
+runInInjectionContext(injector, () =>
+ injectIsFetching(() => ({ queryKey: ['todos'] })),
+) // [!code ++]
+
+injectIsRestoring({ injector }) // [!code --]
+runInInjectionContext(injector, () => injectIsRestoring()) // [!code ++]
+```
+
+Import `runInInjectionContext` from `@angular/core`. Unlike these helpers,
+`injectQueries` previously took the injector directly, as shown above. When the
+old argument is `undefined` or an empty options object, remove it and ensure the
+call already runs in an injection context.
+
+The `InjectQueryOptions`, `InjectInfiniteQueryOptions`, `InjectMutationOptions`,
+`InjectMutationStateOptions`, `InjectIsFetchingOptions`, and
+`InjectIsMutatingOptions` types have also been removed, along with the devtools
+`InjectDevtoolsPanelOptions` type. Update wrappers that use
+these types. The schematic reports explicit arguments, spread arguments, and
+imports of these removed types for manual review; it does not infer injector
+handling through custom wrappers.
+
+## Review SSR hydration
+
+`provideTanStackQuery` now dehydrates the server cache into Angular `TransferState` and hydrates it
+in the browser by default. In most SSR applications, no additional setup is necessary.
+
+If your application already performs manual dehydration and hydration, either remove the manual
+implementation or disable the built-in behavior to avoid hydrating the same client twice:
+
+```ts
+provideTanStackQuery(() => new QueryClient(), withNoQueryHydration())
+```
+
+Give each client a unique key when multiple clients use automatic hydration:
+
+```ts
+provideTanStackQuery(
+ () => new QueryClient(),
+ withHydrationKey('admin-query-cache'),
+)
+```
+
+See the [SSR guide](./ssr.md) for request-scoped client setup and the interaction with Angular
+`HttpClient` transfer caching.
+
+## Update tests that wait for stability
+
+Observed queries, parallel queries, and mutations started through the adapter register with Angular's `PendingTasks`.
+As a result, `ApplicationRef.whenStable()` and `fixture.whenStable()` wait until that work settles.
+
+In zone-based component tests, call `fixture.autoDetectChanges()` before awaiting stability.
+Resolve controlled operations before `whenStable()`; assert pending state while they remain
+unresolved. HTTP mutations can start asynchronously, so wait for the request itself before flushing
+it. `isPending()` does not prove that a mocked API has been called.
+
+With fake timers, advance timers and queued microtasks before awaiting stability. Disabled queries
+do not fetch automatically; a manual refetch still registers pending work.
+See [Testing](./testing.md) for query, mutation, HTTP, and fake-timer examples.
+
+After a query-key signal changes, `data()` can immediately return cached data for the new key,
+before another change-detection pass. Assert the state the test intends to observe rather than
+requiring an empty intermediate value.
+
+## Error handling
+
+Observer options no longer include `throwOnError`. Errors are exposed through the result's
+`error`, `status`, and related signals, without an automatic global report. Cached query data
+remains readable when a background refetch fails.
+
+```ts
+injectQuery(() => ({
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+ throwOnError: true,
+})) // [!code --]
+injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })) // [!code ++]
+```
+
+Remove observer `throwOnError` from query, infinite-query, and mutation options, including your
+Angular-specific client defaults. The shared core client still accepts this option for other
+framework adapters, but Angular does not use it for reporting.
+
+`mutateAsync()` still rejects on failure, and `mutate()` still returns void. Imperative options
+such as `query.refetch({ throwOnError: true })` retain their promise-rejection behavior.
+To report cache failures to Angular, use the [ErrorHandler guide](./error-handling.md).
+`toResource(query).value()` throws when the Resource is in its error state; guard the read with
+`hasValue()` or inspect `error()` first.
+
+## Make activity filters reactive
+
+```ts
+injectIsFetching({ queryKey: ['todos'] }) // [!code --]
+injectIsFetching(() => ({ queryKey: ['todos', userId()] })) // [!code ++]
+
+injectIsMutating({ mutationKey: ['save'] }) // [!code --]
+injectIsMutating(() => ({ mutationKey: ['save'] })) // [!code ++]
+```
+
+Calls without filters remain unchanged. Filter factories can read required inputs and signals;
+changing a filter updates the count without waiting for a cache event.
+
+## Imperative methods
+
+Methods such as `refetch()` and `fetchNextPage()` use the current options even when called
+immediately after changing an options signal.
+
+Read the current `injectQueries()` result when calling a method after adding, removing, or
+reordering queries.
+
+`injectMutationState` selections and `injectQueries` combined results are no longer deeply
+compared by the adapter. A newly allocated selected object or combined result can trigger consumers
+even when its contents match the previous value. Prefer returning existing values when possible.
+
+## Stability and notifications
+
+Signal updates no longer enter `NgZone` or wait for adapter microtasks. Angular's change-detection
+scheduler handles rendering. Keep reading reactive values as signals; callbacks do not gain an
+injection context or guaranteed zone membership.
+
+Each mutation invocation blocks stability until its promise settles, including awaited lifecycle
+callbacks. A later invocation completing, or calling `reset()`, does not release an earlier mutation's
+work. Destroying the owning component or injector releases its pending tasks. Queries that are
+paused offline continue to block stability until resumed, cancelled, or unobserved.
+
+## Persistence configuration
+
+Pass a factory to `withPersistQueryClient`:
+
+```ts
+withPersistQueryClient(() => ({
+ persistOptions: { persister },
+}))
+```
+
+The factory runs once per injector, in an injection context, only in the browser.
+Create persisters that access `localStorage` inside this factory.
+
+Persistence manages its restoration state automatically through `withPersistQueryClient`.
+See [persistQueryClient](../plugins/persistQueryClient.md) for the options and persisters.
+
+## New behavior that needs no migration
+
+The stable package also includes the following compatible improvements:
+
+- Query results can be converted into an Angular Resource with `toResource`. See the
+ [Resource API](../resource-api.md).
+- `injectQueries` is supported from the main package with reactive options and field-level signals.
+- Result field signals are evaluated lazily, so options can safely read required input signals without
+ being evaluated during class construction.
+- Persistence options may be supplied as a browser-only factory, making references such as
+ `localStorage` safe in SSR applications.
diff --git a/docs/framework/angular/guides/migrating-from-ngneat-query.md b/docs/framework/angular/guides/migrating-from-ngneat-query.md
new file mode 100644
index 00000000000..946bb526d2d
--- /dev/null
+++ b/docs/framework/angular/guides/migrating-from-ngneat-query.md
@@ -0,0 +1,295 @@
+---
+id: migrating-from-ngneat-query
+title: Migrating from ngneat/query
+---
+
+Angular Query requires Angular 20.1 or newer.
+
+This guide uses `@ngneat/query` in its examples.
+
+## Active codebase recommendations
+
+For a gradual migration:
+
+- Install `@tanstack/angular-query` alongside the legacy package and share one `QueryClient`,
+ so migrated and existing code use the same cache, defaults, and invalidations.
+- Block `@ngneat/query` imports and its subpaths with ESLint's
+ [`no-restricted-imports`](https://eslint.org/docs/latest/rules/no-restricted-imports) or a
+ similar rule, so new code uses `@tanstack/angular-query`.
+- Share a test-provider helper or client factory so migrated tests keep the same client defaults.
+
+Suppress existing imports and the temporary provider bridge with
+[ESLint suppressions](https://eslint.org/docs/latest/use/suppressions) or a
+[rule-specific disable comment](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1),
+and remove each suppression as its import is migrated.
+
+Keep the existing ngneat client configuration and let the stable adapter resolve that client:
+
+```ts
+import { ApplicationConfig } from '@angular/core'
+import {
+ injectQueryClient as injectLegacyQueryClient,
+ provideQueryClientOptions,
+} from '@ngneat/query'
+import { provideTanStackQuery } from '@tanstack/angular-query'
+
+export const appConfig: ApplicationConfig = {
+ providers: [
+ provideQueryClientOptions({
+ // Keep your existing client options here.
+ }),
+ provideTanStackQuery(() => injectLegacyQueryClient()),
+ ],
+}
+```
+
+This preserves the legacy client's Observable-aware methods while both adapters use the same
+instance. Keep query keys consistent between migrated and legacy code.
+
+Use package versions that support the same Angular and `@tanstack/query-core` versions. If the
+lockfile selects different core versions, align the direct core dependency required by ngneat
+with the stable adapter's dependency. You may need root-level
+[npm overrides](https://docs.npmjs.com/cli/v11/configuring-npm/package-json/#overrides) or
+[pnpm overrides](https://pnpm.io/settings#overrides) to select one version within both supported
+ranges.
+
+After migrating the remaining legacy code, replace the bridge with a `QueryClient` factory from
+`@tanstack/angular-query`, move the client options into that factory, and remove the legacy packages.
+
+## Replace the packages
+
+Remove whichever legacy package name your application uses, along with its devtools package. The
+stable adapter includes `@tanstack/query-core` as a dependency, so remove a direct installation
+unless your application imports it independently.
+
+```sh
+npm uninstall @ngneat/query @ngneat/query-devtools @tanstack/query-core
+npm install @tanstack/angular-query @tanstack/angular-query-devtools
+```
+
+## Configure the `QueryClient`
+
+Replace `provideQueryClientOptions` with a `QueryClient` factory passed to
+`provideTanStackQuery`. The factory runs in an Angular injection context, so it can call `inject()`
+when building caches or default options.
+
+```ts
+import { QueryCache } from '@ngneat/query' // [!code --]
+import { provideQueryClientOptions } from '@ngneat/query' // [!code --]
+import { QueryCache, QueryClient } from '@tanstack/angular-query' // [!code ++]
+import { provideTanStackQuery } from '@tanstack/angular-query' // [!code ++]
+
+const queryClientConfig = {
+ queryCache: new QueryCache({ onError: handleError }),
+}
+
+providers: [
+ provideQueryClientOptions(queryClientConfig), // [!code --]
+ provideTanStackQuery(() => new QueryClient(queryClientConfig)), // [!code ++]
+]
+```
+
+## Migrate queries
+
+The legacy `injectQuery()` call returned a function that accepted query options. The stable API
+accepts a reactive options callback and returns the query result directly.
+
+```ts
+private readonly useQuery = injectQuery() // [!code --]
+
+readonly todos = this.useQuery({ // [!code --]
+ queryKey: ['todos'], // [!code --]
+ queryFn: fetchTodos, // [!code --]
+}) // [!code --]
+readonly todos = injectQuery(() => ({ // [!code ++]
+ queryKey: ['todos'], // [!code ++]
+ queryFn: fetchTodos, // [!code ++]
+})) // [!code ++]
+```
+
+Read signals inside the callback to update options reactively. This replaces calling
+`updateOptions` yourself.
+
+```ts
+readonly filter = signal('')
+private readonly useQuery = injectQuery() // [!code --]
+readonly todos = this.useQuery({ // [!code --]
+ queryKey: ['todos', this.filter()], // [!code --]
+ queryFn: () => fetchTodos(this.filter()), // [!code --]
+}) // [!code --]
+readonly todos = injectQuery(() => ({ // [!code ++]
+ queryKey: ['todos', this.filter()], // [!code ++]
+ queryFn: () => fetchTodos(this.filter()), // [!code ++]
+})) // [!code ++]
+```
+
+When a helper must be called from a callback that is not already in an injection context, use
+Angular's `runInInjectionContext` at the call site:
+
+```ts
+runInInjectionContext(injector, () => injectQuery(() => queryOptions))
+```
+
+## Migrate infinite queries and mutations
+
+`injectInfiniteQuery` and `injectMutation` use the same callback pattern:
+
+```ts
+private readonly useInfiniteQuery = injectInfiniteQuery() // [!code --]
+readonly posts = this.useInfiniteQuery({ // [!code --]
+ queryKey: ['posts'], // [!code --]
+ queryFn: ({ pageParam }) => fetchPosts(pageParam), // [!code --]
+ initialPageParam: 0, // [!code --]
+ getNextPageParam: (lastPage) => lastPage.nextId, // [!code --]
+}) // [!code --]
+readonly posts = injectInfiniteQuery(() => ({ // [!code ++]
+ queryKey: ['posts'], // [!code ++]
+ queryFn: ({ pageParam }) => fetchPosts(pageParam), // [!code ++]
+ initialPageParam: 0, // [!code ++]
+ getNextPageParam: (lastPage) => lastPage.nextId, // [!code ++]
+})) // [!code ++]
+```
+
+```ts
+private readonly useMutation = injectMutation() // [!code --]
+readonly addTodo = this.useMutation({ // [!code --]
+ mutationFn: addTodo, // [!code --]
+}) // [!code --]
+readonly addTodo = injectMutation(() => ({ // [!code ++]
+ mutationFn: addTodo, // [!code ++]
+})) // [!code ++]
+```
+
+Imperative methods remain direct methods, for example `addTodo.mutate(value)`,
+`addTodo.reset()`, `posts.fetchNextPage()`, and `todos.refetch()`.
+
+## Migrate query and mutation results
+
+The legacy adapter exposed one signal and one Observable containing the entire observer result.
+The stable adapter exposes each result field as a signal and keeps imperative methods as functions.
+
+```ts
+todos.result().isPending // [!code --]
+todos.result().data // [!code --]
+todos.result().error // [!code --]
+todos.isPending() // [!code ++]
+todos.data() // [!code ++]
+todos.error() // [!code ++]
+```
+
+Templates use the field signals in the same way:
+
+```angular-html
+@if (todos.result().isPending) {
+@if (todos.isPending()) {
+ Loading...
+} @else if (todos.isError()) {
+ {{ todos.error()?.message }}
+} @else {
+ @for (todo of todos.data(); track todo.id) {
+ {{ todo.title }}
+ }
+}
+```
+
+There is no direct replacement for `result$`. Convert the field signal you need with Angular's
+`toObservable`, or compose several fields with `computed` first.
+
+```ts
+readonly todosResult$ = this.todos.result$ // [!code --]
+readonly todosState = computed(() => ({ // [!code ++]
+ data: this.todos.data(), // [!code ++]
+ error: this.todos.error(), // [!code ++]
+ status: this.todos.status(), // [!code ++]
+})) // [!code ++]
+readonly todosResult$ = toObservable(this.todosState) // [!code ++]
+```
+
+Mutation state follows the same rule:
+
+```ts
+addTodo.result().isPending // [!code --]
+addTodo.result().data // [!code --]
+addTodo.isPending() // [!code ++]
+addTodo.data() // [!code ++]
+```
+
+## Convert Observable query functions
+
+The legacy adapter accepted an RxJS `Observable` from `queryFn` and `mutationFn`. The stable
+adapter follows TanStack Query's Promise-based contract, so convert an Observable with
+`firstValueFrom` or `lastValueFrom`.
+
+```ts
+queryFn: () => this.http.get('/api/todos') // [!code --]
+queryFn: () => lastValueFrom(this.http.get('/api/todos')) // [!code ++]
+```
+
+```ts
+const createTodo = (todo: Todo) => this.http.post('/api/todos', todo)
+
+mutationFn: createTodo // [!code --]
+mutationFn: (todo) => lastValueFrom(createTodo(todo)) // [!code ++]
+```
+
+See [Angular HttpClient](../angular-httpclient-and-other-data-fetching-clients.md)
+for a complete example. If an Observable does not complete, prefer `firstValueFrom` or make it
+complete before converting it.
+
+## Migrate background indicators
+
+`injectIsFetching` and `injectIsMutating` now accept a reactive filters callback and return a
+`Signal`.
+
+```ts
+private readonly useIsFetching = injectIsFetching() // [!code --]
+readonly fetchingTodos = // [!code --]
+ this.useIsFetching({ queryKey: ['todos'] }).toSignal() // [!code --]
+readonly fetchingTodos = injectIsFetching(() => ({ queryKey: ['todos'] })) // [!code ++]
+```
+
+```ts
+private readonly useIsMutating = injectIsMutating() // [!code --]
+readonly mutatingTodos = // [!code --]
+ this.useIsMutating({ mutationKey: ['todos'] }).toSignal() // [!code --]
+readonly mutatingTodos = injectIsMutating(() => ({ mutationKey: ['todos'] })) // [!code ++]
+```
+
+Use `toObservable(this.fetchingTodos)` if a consumer still needs an Observable.
+
+## Inject the `QueryClient`
+
+Use Angular dependency injection directly instead of `injectQueryClient`:
+
+```ts
+import { injectQueryClient } from '@ngneat/query' // [!code --]
+import { inject } from '@angular/core' // [!code ++]
+import { QueryClient } from '@tanstack/angular-query' // [!code ++]
+
+private readonly queryClient = injectQueryClient() // [!code --]
+private readonly queryClient = inject(QueryClient) // [!code ++]
+```
+
+## Migrate devtools
+
+Replace the legacy devtools provider with the `withDevtools` feature from the standalone Angular
+Query devtools package.
+
+```ts
+import { provideQueryClientOptions } from '@ngneat/query' // [!code --]
+import { provideQueryDevTools } from '@ngneat/query-devtools' // [!code --]
+import { QueryClient, provideTanStackQuery } from '@tanstack/angular-query' // [!code ++]
+import { withDevtools } from '@tanstack/angular-query-devtools' // [!code ++]
+
+const devtools = withDevtools(() => ({ initialIsOpen: true }))
+
+providers: [
+ provideQueryClientOptions({}), // [!code --]
+ provideQueryDevTools({ initialIsOpen: true }), // [!code --]
+ provideTanStackQuery(() => new QueryClient(), devtools), // [!code ++]
+]
+```
+
+See the [Devtools guide](../devtools.md) for production entrypoints and reactive options.
+
+See [Error handling](./error-handling.md) for optional Angular `ErrorHandler` integration.
diff --git a/docs/framework/angular/guides/migrating-to-angular-query.md b/docs/framework/angular/guides/migrating-to-angular-query.md
new file mode 100644
index 00000000000..393d15ea7cc
--- /dev/null
+++ b/docs/framework/angular/guides/migrating-to-angular-query.md
@@ -0,0 +1,11 @@
+---
+id: migrating-to-angular-query
+title: Migrating to Angular Query
+---
+
+Choose the guide for your current adapter:
+
+- [Migrating from Angular Query Experimental](./migrating-from-experimental.md)
+- [Migrating from ngneat/query or openng/query](./migrating-from-ngneat-query.md)
+
+Both target Angular 20.1 or newer.
diff --git a/docs/framework/angular/guides/mutations.md b/docs/framework/angular/guides/mutations.md
index 04918de21f9..ea3e53cd2ab 100644
--- a/docs/framework/angular/guides/mutations.md
+++ b/docs/framework/angular/guides/mutations.md
@@ -274,3 +274,5 @@ queryClient.resumePausedMutations()
[//]: # 'OfflineExampleLink'
[//]: # 'Materials'
[//]: # 'Materials'
+
+See [Error handling](./error-handling.md) to connect cache failures to Angular’s `ErrorHandler`.
diff --git a/docs/framework/angular/guides/parallel-queries.md b/docs/framework/angular/guides/parallel-queries.md
index 8e2e2348fc5..d6071e9d3b3 100644
--- a/docs/framework/angular/guides/parallel-queries.md
+++ b/docs/framework/angular/guides/parallel-queries.md
@@ -17,6 +17,9 @@ replace:
[//]: # 'Example'
```ts
+@Component({
+ // ...
+})
export class AppComponent {
// The following queries will execute in parallel
readonly usersQuery = injectQuery(() => ({
@@ -45,12 +48,14 @@ TanStack Query provides `injectQueries`, which you can use to dynamically execut
[//]: # 'Example2'
```ts
+@Component({
+ // ...
+})
export class AppComponent {
users = signal>([])
- // Please note injectQueries is under development and this code does not work yet
- readonly userQueries = injectQueries(() => ({
- queries: users().map((user) => {
+ userQueries = injectQueries(() => ({
+ queries: this.users().map((user) => {
return {
queryKey: ['user', user.id],
queryFn: () => fetchUserById(user.id),
diff --git a/docs/framework/angular/guides/queries.md b/docs/framework/angular/guides/queries.md
index 051d332bf8a..1bf5816d206 100644
--- a/docs/framework/angular/guides/queries.md
+++ b/docs/framework/angular/guides/queries.md
@@ -6,6 +6,7 @@ replace:
{
'React': 'Angular',
'react-query': 'angular-query',
+ '@tanstack/angular-query': '@tanstack/angular-query',
'promise': 'promise or observable',
'custom hooks': 'services',
'the `useQuery` hook': '`injectQuery`',
@@ -17,7 +18,7 @@ replace:
[//]: # 'Example'
```ts
-import { injectQuery } from '@tanstack/angular-query-experimental'
+import { injectQuery } from '@tanstack/angular-query'
export class TodosComponent {
readonly todosQuery = injectQuery(() => ({
@@ -101,4 +102,11 @@ class TodosComponent {}
[//]: # 'Example4'
[//]: # 'Materials'
+
+Angular Query can convert each query result into a Resource-compatible view with `toResource`. See
+the [Resource API](../resource-api.md) when an Angular API expects a
+[Resource](https://angular.dev/api/core/Resource).
+
[//]: # 'Materials'
+
+See [Error handling](./error-handling.md) to connect cache failures to Angular’s `ErrorHandler`.
diff --git a/docs/framework/angular/guides/query-cancellation.md b/docs/framework/angular/guides/query-cancellation.md
index 100ced3c981..8ca511ca000 100644
--- a/docs/framework/angular/guides/query-cancellation.md
+++ b/docs/framework/angular/guides/query-cancellation.md
@@ -14,10 +14,11 @@ However, if you consume the `AbortSignal`, the Promise will be cancelled (e.g. a
## Using `HttpClient`
```ts
-import { injectQuery } from '@tanstack/angular-query-experimental'
import { fromEvent, lastValueFrom, takeUntil } from 'rxjs'
+import { injectQuery } from '@tanstack/angular-query'
postQuery = injectQuery(() => ({
+ enabled: this.postId() > 0,
queryKey: ['post', this.postId()],
queryFn: (context): Promise => {
const abort$ = fromEvent(context.signal, 'abort')
@@ -96,7 +97,7 @@ export class TodosComponent {
readonly queryClient = inject(QueryClient)
onCancel() {
- this.queryClient.cancelQueries({ queryKey: ['todos'] })
+ this.queryClient.cancelQueries(['todos'])
}
}
```
diff --git a/docs/framework/angular/guides/query-invalidation.md b/docs/framework/angular/guides/query-invalidation.md
index 36956557dcf..eb287dd0070 100644
--- a/docs/framework/angular/guides/query-invalidation.md
+++ b/docs/framework/angular/guides/query-invalidation.md
@@ -8,7 +8,7 @@ replace: { 'useQuery': 'injectQuery', 'hooks': 'functions' }
[//]: # 'Example2'
```ts
-import { injectQuery, QueryClient } from '@tanstack/angular-query-experimental'
+import { injectQuery, QueryClient } from '@tanstack/angular-query'
class QueryInvalidationExample {
readonly queryClient = inject(QueryClient)
diff --git a/docs/framework/angular/guides/query-options.md b/docs/framework/angular/guides/query-options.md
index eb90770d815..691b52ec4fd 100644
--- a/docs/framework/angular/guides/query-options.md
+++ b/docs/framework/angular/guides/query-options.md
@@ -7,7 +7,7 @@ ref: docs/framework/react/guides/query-options.md
[//]: # 'Example1'
```ts
-import { queryOptions, noop } from '@tanstack/angular-query-experimental'
+import { noop, queryOptions } from '@tanstack/angular-query'
@Injectable({
providedIn: 'root',
@@ -38,7 +38,7 @@ queries = inject(QueriesService)
postQuery = injectQuery(() => this.queries.post(this.postId()))
-queryClient.query(this.queries.post(23)).catch(noop)
+void queryClient.query(this.queries.post(23)).catch(noop)
queryClient.setQueryData(this.queries.post(42).queryKey, newPost)
```
diff --git a/docs/framework/angular/guides/query-retries.md b/docs/framework/angular/guides/query-retries.md
index a7b0b1841ca..e19c8f85a37 100644
--- a/docs/framework/angular/guides/query-retries.md
+++ b/docs/framework/angular/guides/query-retries.md
@@ -15,7 +15,7 @@ replace:
[//]: # 'Example'
```ts
-import { injectQuery } from '@tanstack/angular-query-experimental'
+import { injectQuery } from '@tanstack/angular-query'
// Make a specific query retry a certain number of times
const todoQuery = injectQuery(() => ({
@@ -33,19 +33,20 @@ const todoQuery = injectQuery(() => ({
import {
QueryCache,
QueryClient,
- provideTanStackQuery,
-} from '@tanstack/angular-query-experimental'
+ QueryClientProvider,
+} from '@tanstack/angular-query'
-const queryClient = new QueryClient({
- defaultOptions: {
- queries: {
- retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
+const createQueryClient = () =>
+ new QueryClient({
+ defaultOptions: {
+ queries: {
+ retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
+ },
},
- },
-})
+ })
bootstrapApplication(AppComponent, {
- providers: [provideTanStackQuery(queryClient)],
+ providers: [provideTanStackQuery(createQueryClient)],
})
```
diff --git a/docs/framework/angular/guides/ssr.md b/docs/framework/angular/guides/ssr.md
new file mode 100644
index 00000000000..2b6b727796f
--- /dev/null
+++ b/docs/framework/angular/guides/ssr.md
@@ -0,0 +1,101 @@
+---
+id: ssr
+title: SSR
+---
+
+For [Angular SSR](https://angular.dev/guide/ssr), [`provideTanStackQuery`](../reference/functions/provideTanStackQuery.md) serializes the `QueryClient` cache into Angular's `TransferState` and restores it when the browser application starts.
+
+See the [Angular SSR example](https://github.com/TanStack/query/tree/main/examples/angular/ssr). The
+[SSR persistence example](https://github.com/TanStack/query/tree/main/examples/angular/ssr-persist)
+builds on the same setup with browser persistence.
+
+## Query client factory
+
+```ts
+import { isPlatformBrowser } from '@angular/common'
+import { inject, PLATFORM_ID } from '@angular/core'
+import { QueryClient } from '@tanstack/angular-query'
+
+export function createQueryClient() {
+ const isBrowser = isPlatformBrowser(inject(PLATFORM_ID))
+
+ return new QueryClient({
+ defaultOptions: {
+ queries: {
+ // Retry failed queries in the browser, but not on the server.
+ retry: isBrowser ? 3 : 0,
+ },
+ },
+ })
+}
+```
+
+## Browser config
+
+Use the factory with `provideTanStackQuery` in your application config. Angular's HTTP transfer
+cache is enabled by default with
+[`provideClientHydration`](https://angular.dev/api/platform-browser/provideClientHydration). Add
+[`withNoHttpTransferCache`](https://angular.dev/api/platform-browser/withNoHttpTransferCache) so
+query results are not serialized once by each cache.
+
+```ts
+import type { ApplicationConfig } from '@angular/core'
+import { provideHttpClient } from '@angular/common/http'
+import {
+ provideClientHydration,
+ withEventReplay,
+ withNoHttpTransferCache,
+} from '@angular/platform-browser'
+import { provideTanStackQuery } from '@tanstack/angular-query'
+import { withDevtools } from '@tanstack/angular-query-devtools'
+import { createQueryClient } from './query-client'
+
+export const appConfig: ApplicationConfig = {
+ providers: [
+ provideHttpClient(),
+ provideClientHydration(withEventReplay(), withNoHttpTransferCache()),
+ provideTanStackQuery(createQueryClient, withDevtools()),
+ ],
+}
+```
+
+## Server config
+
+Merge the application config with `provideServerRendering` in the server config.
+
+```ts
+import { mergeApplicationConfig } from '@angular/core'
+import { provideServerRendering, withRoutes } from '@angular/ssr'
+import { appConfig } from './app.config'
+import { serverRoutes } from './app.routes.server'
+
+export const serverConfig = mergeApplicationConfig(appConfig, {
+ providers: [provideServerRendering(withRoutes(serverRoutes))],
+})
+```
+
+## Multiple query clients
+
+Built-in hydration uses a default transfer key. For a second `QueryClient` in a child injector, pass a distinct key with `withHydrationKey` so each client's serialized cache stays separate.
+
+```ts
+providers: [
+ provideTanStackQuery(
+ createSecondaryQueryClient,
+ withHydrationKey('my-secondary-query-cache'),
+ ),
+]
+```
+
+## Disabling built-in hydration
+
+If you need to opt out of TanStack Query's built-in `TransferState` integration for a specific injector, add `withNoQueryHydration()`.
+
+```ts
+providers: [provideTanStackQuery(createQueryClient, withNoQueryHydration())]
+```
+
+## See also
+
+- [Angular HttpClient and data fetching](../angular-httpclient-and-other-data-fetching-clients.md)
+- [Devtools](../devtools.md)
diff --git a/docs/framework/angular/guides/testing.md b/docs/framework/angular/guides/testing.md
index 857b2a57ee0..007fdca2545 100644
--- a/docs/framework/angular/guides/testing.md
+++ b/docs/framework/angular/guides/testing.md
@@ -7,13 +7,13 @@ Most Angular tests using TanStack Query will involve services or components that
TanStack Query's `inject*` functions integrate with [`PendingTasks`](https://angular.dev/api/core/PendingTasks) which ensures the framework is aware of in-progress queries and mutations.
-This lets the framework, for example during SSR, wait until mutations and queries resolve. In unit tests, `ApplicationRef.whenStable()` and `fixture.whenStable()` work for both Zone.js and Zoneless setups when the work settles right away, such as a synchronous query function or a response flushed through `HttpTestingController`. They can resolve before a query or mutation that takes time settles, so advance fake timers instead, as shown in the sections below.
+This means tests and SSR can wait until mutations and queries resolve. In unit tests you can use `ApplicationRef.whenStable()` or `fixture.whenStable()` to await query completion. This works for both Zone.js and Zoneless setups.
-> This integration requires Angular 19 or later. Earlier versions of Angular do not support `PendingTasks`.
+> This adapter requires Angular 20.1 or later. It uses `PendingTasks` to keep application stability open while observed work is pending.
## TestBed setup
-Create a fresh `QueryClient` for every spec and provide it with `provideTanStackQuery` or `provideQueryClient`. This keeps caches isolated and lets you change default options per test:
+Create a fresh `QueryClient` for every spec and return it from the provider factory. Keeping a reference makes it easy to inspect or clear the cache:
```ts
const queryClient = new QueryClient({
@@ -25,11 +25,11 @@ const queryClient = new QueryClient({
})
TestBed.configureTestingModule({
- providers: [provideTanStackQuery(queryClient)],
+ providers: [provideTanStackQuery(() => queryClient)],
})
```
-> If your applications actual TanStack Query config is used in unit tests, make sure `withDevtools` is not accidentally included in test providers. This can cause slow tests. It is best to keep test and production configs separate.
+> If your application's TanStack Query config is used in unit tests, make sure `withDevtools` is not accidentally included in test providers. This can cause slow tests. It is best to keep test and production configs separate.
If you share helpers, remember to call `queryClient.clear()` (or build a new instance) in `afterEach` so data from one test never bleeds into another.
@@ -46,7 +46,7 @@ const query = TestBed.runInInjectionContext(() =>
})),
)
-TestBed.tick() // Trigger effect
+TestBed.tick() // Synchronize the test application
// Application is stable when queries are idle
await appRef.whenStable()
@@ -55,7 +55,7 @@ expect(query.status()).toBe('success')
expect(query.data()).toBe('Hello')
```
-Here `whenStable()` resolves after the query settles because the query function returns right away. When using fake timers (Vitest), advance the clock and a microtask before awaiting stability:
+PendingTasks will have `whenStable()` resolve after the query settles. When using fake timers (Vitest), advance the clock and a microtask before awaiting stability:
```ts
await vi.advanceTimersByTimeAsync(0)
@@ -65,89 +65,22 @@ await appRef.whenStable()
## Testing components
-For components, create them through `TestBed.createComponent`. `fixture.whenStable()` can resolve before the query data arrives, so with fake timers, advance the clock past the query function's delay, then run `fixture.detectChanges()` and assert on what the component renders:
+For components, bootstrap them through `TestBed.createComponent`, then await `fixture.whenStable()`:
-```angular-ts
-beforeEach(() => {
- vi.useFakeTimers()
-})
-
-afterEach(() => {
- vi.useRealTimers()
-})
-
-it('should render the query data', async () => {
- @Component({
- template: `
{{ query.data()?.value ?? 'Loading...' }}
`,
- })
- class ExampleComponent {
- readonly query = injectQuery(() => ({
- queryKey: ['example'],
- queryFn: () =>
- new Promise<{ value: number }>((resolve) =>
- setTimeout(() => resolve({ value: 42 }), 10),
- ),
- }))
- }
-
- const fixture = TestBed.createComponent(ExampleComponent)
- fixture.detectChanges()
- expect(fixture.nativeElement.textContent).toContain('Loading...')
-
- await vi.advanceTimersByTimeAsync(11)
- fixture.detectChanges()
-
- expect(fixture.nativeElement.textContent).toContain('42')
-})
-```
+```ts
+const fixture = TestBed.createComponent(ExampleComponent)
+fixture.autoDetectChanges()
-If you use [Angular Testing Library](https://testing-library.com/docs/angular-testing-library/intro/), render the component with `render` and follow the same flow, running change detection through `rendered.fixture`:
-
-```angular-ts
-it('should render the query data', async () => {
- @Component({
- template: `
{{ query.data()?.value ?? 'Loading...' }}
`,
- })
- class ExampleComponent {
- readonly query = injectQuery(() => ({
- queryKey: ['example'],
- queryFn: () =>
- new Promise<{ value: number }>((resolve) =>
- setTimeout(() => resolve({ value: 42 }), 10),
- ),
- }))
- }
-
- const rendered = await render(ExampleComponent)
- expect(rendered.getByText('Loading...')).toBeInTheDocument()
-
- await vi.advanceTimersByTimeAsync(11)
- rendered.fixture.detectChanges()
-
- expect(rendered.getByText('42')).toBeInTheDocument()
-})
+await fixture.whenStable()
+expect(fixture.componentInstance.query.data()).toEqual({ value: 42 })
```
-To test the same query without a component, create it with `TestBed.runInInjectionContext`, advance the clock the same way, and assert on its signals:
+In zone-based tests, enable `fixture.autoDetectChanges()` so component effects can run again
+as the query settles. Zoneless fixtures enable automatic detection by default.
-```ts
-it('should resolve the query data', async () => {
- const query = TestBed.runInInjectionContext(() =>
- injectQuery(() => ({
- queryKey: ['example'],
- queryFn: () =>
- new Promise<{ value: number }>((resolve) =>
- setTimeout(() => resolve({ value: 42 }), 10),
- ),
- })),
- )
- expect(query.isPending()).toBe(true)
-
- await vi.advanceTimersByTimeAsync(11)
-
- expect(query.data()).toEqual({ value: 42 })
-})
-```
+When using Angular Testing Library, its `autoDetectChanges` option runs change detection around
+library operations; it does not call `fixture.autoDetectChanges()`. Enable the fixture's automatic
+detection explicitly when awaiting stability in a zone-based component test.
## Handling retries
@@ -155,14 +88,16 @@ Retries slow failing tests because the default backoff runs three times. Set `re
## HttpClient & network stubs
-Angular's `HttpClient` testing utilities play nicely with PendingTasks. Register `provideHttpClient()` and `provideHttpClientTesting()` alongside the Query provider and flush responses through `HttpTestingController`:
+Angular's `provideHttpClientTesting` plays nicely with PendingTasks. Register it after
+`provideHttpClient`, alongside the Query provider, and flush responses through
+`HttpTestingController`:
```ts
TestBed.configureTestingModule({
providers: [
provideHttpClient(),
provideHttpClientTesting(),
- provideTanStackQuery(queryClient),
+ provideTanStackQuery(() => queryClient),
],
})
@@ -174,6 +109,7 @@ const query = TestBed.runInInjectionContext(() =>
})),
)
+TestBed.tick() // Synchronize the test application so the request starts
const fixturePromise = TestBed.inject(ApplicationRef).whenStable()
httpCtrl.expectOne('/api/todos').flush([{ id: 1 }])
await fixturePromise
@@ -182,69 +118,96 @@ expect(query.data()).toEqual([{ id: 1 }])
httpCtrl.verify()
```
+Mutations can start their HTTP request asynchronously, after their `onMutate` callbacks finish.
+Wait for the request itself before flushing it. This Vitest example uses `vi.waitFor`:
+
+```ts
+const http = TestBed.inject(HttpClient)
+const mutation = TestBed.runInInjectionContext(() =>
+ injectMutation(() => ({
+ mutationFn: (input: { email: string }) =>
+ lastValueFrom(http.post('/api/reset', input)),
+ })),
+)
+
+TestBed.tick()
+mutation.mutate({ email: 'person@example.com' })
+
+const request = await vi.waitFor(() => httpCtrl.expectOne('/api/reset'))
+request.flush({ ok: true })
+await TestBed.inject(ApplicationRef).whenStable()
+
+expect(mutation.isSuccess()).toBe(true)
+httpCtrl.verify()
+```
+
+Do not await stability before flushing a request controlled by the test: the unanswered request
+keeps the query or mutation stuck on pending.
+
+Test observable results after normal Angular initialization and updates. For components, render
+with `fixture.autoDetectChanges()` and await `fixture.whenStable()` when the operation should finish.
+For injection-context-only tests, synchronize the test application as shown above. When using
+HTTP mocks or fake timers, flush the request or advance time before awaiting stability.
+
+Avoid asserting an exact subscription order or a stale intermediate value during initialization.
+Those are implementation details. To test pending mutation or fetching state, hold the operation
+open with a controlled promise and assert after rendering; do not await stability until you
+resolve that promise. To test completed state, resolve the operation and await stability before
+asserting the result.
+
## Infinite queries & pagination
-`whenStable()` can resolve before the pages of an infinite query reach the `data()` signal. With fake timers, advance the clock past the query function's delay instead, call `fetchNextPage()`, and advance it again before asserting on `data().pages`. Restore real timers in `afterEach`, so they are restored even when an assertion fails:
+Use the same pattern for infinite queries: call `fetchNextPage()`, advance timers if you are faking time, then await stability and assert on `data().pages`.
```ts
-beforeEach(() => {
- vi.useFakeTimers()
-})
+const infinite = TestBed.runInInjectionContext(() =>
+ injectInfiniteQuery(() => ({
+ queryKey: ['pages'],
+ initialPageParam: 1,
+ queryFn: ({ pageParam }) => fetchPage(pageParam),
+ getNextPageParam: (last, all) => all.length + 1,
+ })),
+)
-afterEach(() => {
- vi.useRealTimers()
-})
+TestBed.tick()
+await appRef.whenStable()
+expect(infinite.data()?.pages).toHaveLength(1)
-it('should load the next page', async () => {
- const infinite = TestBed.runInInjectionContext(() =>
- injectInfiniteQuery(() => ({
- queryKey: ['pages'],
- queryFn: ({ pageParam }) =>
- new Promise((resolve) =>
- setTimeout(() => resolve(`page ${pageParam}`), 10),
- ),
- initialPageParam: 1,
- getNextPageParam: (_lastPage, allPages) => allPages.length + 1,
- })),
- )
-
- await vi.advanceTimersByTimeAsync(11)
- expect(infinite.data()?.pages).toEqual(['page 1'])
-
- void infinite.fetchNextPage()
- await vi.advanceTimersByTimeAsync(11)
- expect(infinite.data()?.pages).toEqual(['page 1', 'page 2'])
-})
+await infinite.fetchNextPage()
+await appRef.whenStable()
+
+expect(infinite.data()?.pages).toHaveLength(2)
```
## Mutations and optimistic updates
-`whenStable()` can resolve before a mutation started with `mutate()` settles. With fake timers enabled as in the examples above, advance the clock past the mutation function's delay before asserting on the result:
-
```ts
-it('should uppercase the input', async () => {
- const mutation = TestBed.runInInjectionContext(() =>
- injectMutation(() => ({
- mutationFn: (input: string) =>
- new Promise((resolve) =>
- setTimeout(() => resolve(input.toUpperCase()), 10),
- ),
- })),
- )
-
- mutation.mutate('test')
- await vi.advanceTimersByTimeAsync(11)
-
- expect(mutation.isSuccess()).toBe(true)
- expect(mutation.data()).toBe('TEST')
-})
+const mutation = TestBed.runInInjectionContext(() =>
+ injectMutation(() => ({
+ mutationFn: async (input: string) => input.toUpperCase(),
+ })),
+)
+
+mutation.mutate('test')
+
+// Synchronize the test application
+TestBed.tick()
+
+await appRef.whenStable()
+
+expect(mutation.isSuccess()).toBe(true)
+expect(mutation.data()).toBe('TEST')
```
+`whenStable()` waits for every mutation invocation, including awaited lifecycle callbacks.
+Resolve or reject all outstanding mocked mutations before awaiting stability; calling `reset()`
+does not finish a request. Queries paused offline also keep stability open until resumed or cancelled.
+
## Quick checklist
- Fresh `QueryClient` per test (and clear it afterwards)
- Disable or control retries to avoid timeouts
- Advance timers + microtasks before `whenStable()` when using fake timers
-- Use `provideHttpClientTesting()` or your preferred mock to assert network calls
-- Advance timers past the query or mutation function after every `refetch`, `fetchNextPage()`, or mutation instead of awaiting `whenStable()`
-- Prefer `TestBed.runInInjectionContext` for service tests, and `TestBed.createComponent` or Angular Testing Library's `render` with `fixture.detectChanges()` for component tests
+- Use `provideHttpClientTesting` or your preferred mock to assert network calls
+- Resolve controlled requests, then await `whenStable()` for settled-state assertions
+- Prefer `TestBed.runInInjectionContext` for service tests and `fixture.whenStable()` for component tests
diff --git a/docs/framework/angular/guides/window-focus-refetching.md b/docs/framework/angular/guides/window-focus-refetching.md
index 14490ba07ca..36e446238df 100644
--- a/docs/framework/angular/guides/window-focus-refetching.md
+++ b/docs/framework/angular/guides/window-focus-refetching.md
@@ -2,7 +2,7 @@
id: window-focus-refetching
title: Window Focus Refetching
ref: docs/framework/react/guides/window-focus-refetching.md
-replace: { '@tanstack/react-query': '@tanstack/angular-query-experimental' }
+replace: { '@tanstack/react-query': '@tanstack/angular-query' }
---
[//]: # 'Example'
@@ -11,13 +11,14 @@ replace: { '@tanstack/react-query': '@tanstack/angular-query-experimental' }
export const appConfig: ApplicationConfig = {
providers: [
provideTanStackQuery(
- new QueryClient({
- defaultOptions: {
- queries: {
- refetchOnWindowFocus: false, // default: true
+ () =>
+ new QueryClient({
+ defaultOptions: {
+ queries: {
+ refetchOnWindowFocus: false, // default: true
+ },
},
- },
- }),
+ }),
),
],
}
diff --git a/docs/framework/angular/installation.md b/docs/framework/angular/installation.md
index 8ef7db4377b..0ff08b61afb 100644
--- a/docs/framework/angular/installation.md
+++ b/docs/framework/angular/installation.md
@@ -3,32 +3,45 @@ id: installation
title: Installation
---
-> IMPORTANT: This library is currently in an experimental stage. This means that breaking changes will happen in minor AND patch releases. Upgrade carefully. If you use this in production while in experimental stage, please lock your version to a patch-level version to avoid unexpected breaking changes.
+_Angular Query is compatible with Angular v20.1 and higher._
-### NPM
+### Angular CLI
```sh
-npm i @tanstack/angular-query-experimental
+ng add @tanstack/angular-query
+```
+
+This installs the package and devtools, then configures an SSR-safe `QueryClient` factory with
+`withDevtools()`.
+
+### Package managers
+
+```sh
+npm i @tanstack/angular-query
```
or
```sh
-pnpm add @tanstack/angular-query-experimental
+pnpm add @tanstack/angular-query
```
or
```sh
-yarn add @tanstack/angular-query-experimental
+yarn add @tanstack/angular-query
```
or
```sh
-bun add @tanstack/angular-query-experimental
+bun add @tanstack/angular-query
```
-Angular Query is compatible with Angular v16+.
+If you want Angular Query devtools, install the standalone devtools package as well:
+
+```sh
+npm i @tanstack/angular-query-devtools
+```
-> Wanna give it a spin before you download? Try out the [simple](./examples/simple) or [basic](./examples/basic) examples!
+> Want to try it first? See the [simple](./examples/simple) or [basic](./examples/basic) example.
diff --git a/docs/framework/angular/overview.md b/docs/framework/angular/overview.md
index ac71df931f1..67bb8c72bad 100644
--- a/docs/framework/angular/overview.md
+++ b/docs/framework/angular/overview.md
@@ -1,19 +1,17 @@
---
id: overview
title: Overview
+redirect_from:
+ - framework/angular/zoneless
---
-> IMPORTANT: This library is currently in an experimental stage. This means that breaking changes will happen in minor AND patch releases. Upgrade carefully. If you use this in production while in experimental stage, please lock your version to a patch-level version to avoid unexpected breaking changes.
+The `@tanstack/angular-query` package offers a 1st-class API for using TanStack Query via Angular.
-The `@tanstack/angular-query-experimental` package offers a 1st-class API for using TanStack Query via Angular.
-
-## Feedback welcome!
-
-We are in the process of getting to a stable API for TanStack Query on Angular. If you have any feedback, please contact us at the [TanStack Discord](https://tlinz.com/discord) server or [visit this discussion](https://github.com/TanStack/query/discussions/6293) on Github.
+If you have any feedback, please contact us at the [TanStack Discord](https://tlinz.com/discord) server or [visit this discussion](https://github.com/TanStack/query/discussions/6293) on Github.
## Supported Angular Versions
-TanStack Query is compatible with Angular v16 and higher.
+TanStack Query is compatible with Angular v20.1 and higher. Because the adapter is built on signals, it supports zoneless change detection as well as Zone.js.
TanStack Query (FKA React Query) is often described as the missing data-fetching library for web applications, but in more technical terms, it makes **fetching, caching, synchronizing and updating server state** in your web applications a breeze.
@@ -63,7 +61,7 @@ In the example below, you can see TanStack Query in its most basic and simple fo
```angular-ts
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { HttpClient } from '@angular/common/http'
-import { injectQuery } from '@tanstack/angular-query-experimental'
+import { injectQuery } from '@tanstack/angular-query'
import { lastValueFrom } from 'rxjs'
@Component({
@@ -72,11 +70,10 @@ import { lastValueFrom } from 'rxjs'
template: `
@if (repoDataQuery.isPending()) {
Loading...
- }
- @if (repoDataQuery.isError()) {
+ } @else if (repoDataQuery.isError()) {
An error has occurred: {{ repoDataQuery.error().message }}
- }
- @if (repoDataQuery.data(); as data) {
+ } @else if (repoDataQuery.isSuccess()) {
+ @let data = repoDataQuery.data();
{{ data.name }}
{{ data.description }}
👀 {{ data.subscribers_count }}
diff --git a/docs/framework/angular/plugins/persistQueryClient.md b/docs/framework/angular/plugins/persistQueryClient.md
new file mode 100644
index 00000000000..1f48ffb32e1
--- /dev/null
+++ b/docs/framework/angular/plugins/persistQueryClient.md
@@ -0,0 +1,253 @@
+---
+id: persistQueryClient
+title: persistQueryClient
+---
+
+`@tanstack/angular-query-persist-client` saves your `QueryClient` cache with a **persister** and restores it the next time the application starts. Different persisters can store the cache in different storage layers.
+
+## Installation
+
+```sh
+npm install @tanstack/angular-query-persist-client
+```
+
+or
+
+```sh
+pnpm add @tanstack/angular-query-persist-client
+```
+
+or
+
+```sh
+yarn add @tanstack/angular-query-persist-client
+```
+
+or
+
+```sh
+bun add @tanstack/angular-query-persist-client
+```
+
+You also need a persister. `@tanstack/query-async-storage-persister` and `@tanstack/query-sync-storage-persister` provide persisters for the Web Storage API and compatible stores, or you can [build your own](#persisters).
+
+## Usage
+
+Add `withPersistQueryClient` to `provideTanStackQuery`:
+
+```ts
+import { QueryClient, provideTanStackQuery } from '@tanstack/angular-query'
+import { withPersistQueryClient } from '@tanstack/angular-query-persist-client'
+import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'
+import type { ApplicationConfig } from '@angular/core'
+
+export const appConfig: ApplicationConfig = {
+ providers: [
+ provideTanStackQuery(
+ () =>
+ new QueryClient({
+ defaultOptions: {
+ queries: {
+ gcTime: 24 * 60 * 60 * 1000, // 24 hours
+ },
+ },
+ }),
+ withPersistQueryClient(() => ({
+ persistOptions: {
+ persister: createAsyncStoragePersister({ storage: localStorage }),
+ },
+ })),
+ ),
+ ],
+}
+```
+
+The options factory runs once per injector, in an injection context, and only in the browser. It can call `inject()` and use browser APIs such as `localStorage`. During server-side rendering the factory is not called and nothing is restored, so create persisters that access browser storage inside the factory.
+
+When the injector is created in the browser, `withPersistQueryClient`:
+
+1. Restores the persisted cache into the `QueryClient`.
+2. Subscribes to the query cache and saves changes through the persister.
+3. Stops saving when the injector is destroyed.
+
+Restoring is asynchronous. Queries do not start fetching while the cache is being restored. They still render, with `fetchStatus: 'idle'`, until the data has been restored. Then they refetch unless the restored data is fresh enough. `initialData` is respected.
+
+### Options
+
+The factory returns an object with:
+
+- `persistOptions: PersistQueryClientOptions`
+ - all [options](#persistoptions) for persisting and restoring, minus the `QueryClient` itself
+- `onSuccess?: () => Promise | unknown`
+ - optional
+ - will be called when the initial restore is finished
+ - can be used to [resumePausedMutations](../reference/classes/QueryClient.md#resumepausedmutations)
+ - if a Promise is returned, it will be awaited; restoring is seen as ongoing until then
+- `onError?: () => Promise | unknown`
+ - optional
+ - will be called when an error is thrown during restoration
+ - if a Promise is returned, it will be awaited
+
+### `persistOptions`
+
+```ts
+interface PersistQueryClientOptions {
+ /** The Persister interface for storing and restoring the cache
+ * to/from a persisted location */
+ persister: Persister
+ /** The max-allowed age of the cache in milliseconds.
+ * If a persisted cache is found that is older than this
+ * time, it will be **silently** discarded
+ * (defaults to 24 hours) */
+ maxAge?: number
+ /** A unique string that can be used to forcefully
+ * invalidate existing caches if they do not share the same buster string */
+ buster?: string
+ /** The options passed to the hydrate function */
+ hydrateOptions?: HydrateOptions
+ /** The options passed to the dehydrate function */
+ dehydrateOptions?: DehydrateOptions
+}
+```
+
+### injectIsRestoring
+
+Use [`injectIsRestoring`](../reference/functions/injectIsRestoring.md) to check whether a restore is in progress. It returns a signal that is `true` while the cache is being restored. `injectQuery` and friends also check this internally to avoid race conditions between the restore and mounting queries.
+
+```angular-ts
+import { Component } from '@angular/core'
+import { injectIsRestoring } from '@tanstack/angular-query'
+
+@Component({
+ selector: 'app-root',
+ template: `
+ @if (isRestoring()) {
+
Restoring the cache...
+ }
+ `,
+})
+export class AppComponent {
+ readonly isRestoring = injectIsRestoring()
+}
+```
+
+## How It Works
+
+**IMPORTANT** - for persist to work properly, you probably want to pass `QueryClient` a `gcTime` value to override the default during hydration (as shown above).
+
+If it is not set when creating the `QueryClient` instance, it will default to `300000` (5 minutes) for hydration, and the stored cache will be discarded after 5 minutes of inactivity. This is the default garbage collection behavior.
+
+It should be set as the same value or higher than the `maxAge` option. E.g. if `maxAge` is 24 hours (the default) then `gcTime` should be 24 hours or higher. If lower than `maxAge`, garbage collection will kick in and discard the stored cache earlier than expected.
+
+You can also pass it `Infinity` to disable garbage collection behavior entirely.
+
+Due to a JavaScript limitation, the maximum allowed `gcTime` is about [24 days](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#maximum_delay_value), although it is possible to work around this limit using [timeoutManager.setTimeoutProvider](../reference/interfaces/TimeoutManager.md#settimeoutprovider).
+
+### Cache Busting
+
+Sometimes you may make changes to your application or data that immediately invalidate any and all cached data. If and when this happens, you can pass a `buster` string option. If the cache that is found does not also have that buster string, it will be discarded.
+
+```ts
+withPersistQueryClient(() => ({
+ persistOptions: { persister, buster: buildHash },
+}))
+```
+
+### Removal
+
+If data is found to be any of the following:
+
+1. expired (see `maxAge`)
+2. busted (see `buster`)
+3. error (ex: `throws ...`)
+4. empty (ex: `undefined`)
+
+the persister `removeClient()` is called and the cache is immediately discarded.
+
+## Persisters
+
+### Storage persisters
+
+`createAsyncStoragePersister` accepts any storage that adheres to the `AsyncStorage` interface. Storages that read and write synchronously, like `window.localStorage`, also adhere to it.
+
+```ts
+import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'
+
+const persister = createAsyncStoragePersister({ storage: localStorage })
+```
+
+`createSyncStoragePersister` accepts a synchronous storage, such as `window.localStorage` or `window.sessionStorage`.
+
+```ts
+import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
+
+const persister = createSyncStoragePersister({ storage: localStorage })
+```
+
+Both throttle saving to happen at most every 1 second to save on potentially expensive writes.
+
+### Persisters Interface
+
+Persisters have the following interfaces:
+
+```ts
+export interface Persister {
+ persistClient(persistClient: PersistedClient): Promisable
+ restoreClient(): Promisable
+ removeClient(): Promisable
+}
+```
+
+Persisted Client entries have the following interface:
+
+```ts
+export interface PersistedClient {
+ timestamp: number
+ buster: string
+ clientState: DehydratedState
+}
+```
+
+You can import these (to build a persister):
+
+```ts
+import {
+ PersistedClient,
+ Persister,
+} from '@tanstack/angular-query-persist-client'
+```
+
+### Building A Persister
+
+You can persist however you like. Here is an example of how to build an [Indexed DB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) persister. Compared to `Web Storage API`, Indexed DB is faster, stores more than 5MB, and doesn't require serialization. That means it can readily store Javascript native types, such as `Date` and `File`.
+
+```ts
+import { get, set, del } from 'idb-keyval'
+import {
+ PersistedClient,
+ Persister,
+} from '@tanstack/angular-query-persist-client'
+
+/**
+ * Creates an Indexed DB persister
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
+ */
+export function createIDBPersister(idbValidKey: IDBValidKey = 'angularQuery') {
+ return {
+ persistClient: async (client: PersistedClient) => {
+ await set(idbValidKey, client)
+ },
+ restoreClient: async () => {
+ return await get(idbValidKey)
+ },
+ removeClient: async () => {
+ await del(idbValidKey)
+ },
+ } satisfies Persister
+}
+```
+
+## Examples
+
+- [Persister](../examples/basic-persister)
+- [SSR with persistence](../examples/ssr-persist)
diff --git a/docs/framework/angular/quick-start.md b/docs/framework/angular/quick-start.md
index d0033924085..c7358a767af 100644
--- a/docs/framework/angular/quick-start.md
+++ b/docs/framework/angular/quick-start.md
@@ -3,42 +3,25 @@ id: quick-start
title: Quick Start
---
-> IMPORTANT: This library is currently in an experimental stage. This means that breaking changes will happen in minor AND patch releases. Upgrade carefully. If you use this in production while in experimental stage, please lock your version to a patch-level version to avoid unexpected breaking changes.
-
[//]: # 'Example'
If you're looking for a fully functioning example, please have a look at our [basic codesandbox example](./examples/basic)
-### Provide the client to your App
+### Configure the QueryClient
-```ts
-import { provideHttpClient } from '@angular/common/http'
-import {
- provideTanStackQuery,
- QueryClient,
-} from '@tanstack/angular-query-experimental'
-
-bootstrapApplication(AppComponent, {
- providers: [provideHttpClient(), provideTanStackQuery(new QueryClient())],
-})
-```
-
-or in a NgModule-based app
+Pass a factory to `provideTanStackQuery`. Angular runs it once per injector and in an injection context, so it can use `inject()`.
```ts
import { provideHttpClient } from '@angular/common/http'
-import {
- provideTanStackQuery,
- QueryClient,
-} from '@tanstack/angular-query-experimental'
+import { bootstrapApplication } from '@angular/platform-browser'
+import { provideTanStackQuery, QueryClient } from '@tanstack/angular-query'
-@NgModule({
- declarations: [AppComponent],
- imports: [BrowserModule],
- providers: [provideHttpClient(), provideTanStackQuery(new QueryClient())],
- bootstrap: [AppComponent],
+bootstrapApplication(AppComponent, {
+ providers: [
+ provideHttpClient(),
+ provideTanStackQuery(() => new QueryClient()),
+ ],
})
-export class AppModule {}
```
### Component with query and mutation
@@ -52,7 +35,7 @@ import {
injectMutation,
injectQuery,
QueryClient,
-} from '@tanstack/angular-query-experimental'
+} from '@tanstack/angular-query'
@Component({
template: `
diff --git a/docs/framework/angular/reference/functions/infiniteQueryOptions.md b/docs/framework/angular/reference/functions/infiniteQueryOptions.md
index 7af14e4ab67..d9ae08605af 100644
--- a/docs/framework/angular/reference/functions/infiniteQueryOptions.md
+++ b/docs/framework/angular/reference/functions/infiniteQueryOptions.md
@@ -27,7 +27,7 @@ See also: [Parameters](#parameters-summary) · [Returns](#returns-summary)
function infiniteQueryOptions, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(options: DefinedInitialDataInfiniteOptions): DefinedInitialDataInfiniteOptions & QueryKeyWithDataTag, TError>;
```
-Defined in: [packages/angular-query-experimental/src/infinite-query-options.ts:177](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L177)
+Defined in: [packages/angular-query/src/infinite-query-options.ts:177](https://github.com/TanStack/query/blob/main/packages/angular-query/src/infinite-query-options.ts#L177)
You can generally pass everything to `infiniteQueryOptions` that you can also pass to
`injectInfiniteQuery`. These options can be shared across functions and imperative APIs such as
@@ -85,7 +85,7 @@ automatically as the user scrolls.
### Example
```angular-ts
-import { infiniteQueryOptions, injectInfiniteQuery } from '@tanstack/angular-query-experimental'
+import { infiniteQueryOptions, injectInfiniteQuery } from '@tanstack/angular-query'
export const projectsOptions = infiniteQueryOptions({
queryKey: ['projects'],
@@ -122,7 +122,7 @@ export class Projects {
function infiniteQueryOptions, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(options: UnusedSkipTokenInfiniteOptions): UnusedSkipTokenInfiniteOptions & QueryKeyWithDataTag, TError>;
```
-Defined in: [packages/angular-query-experimental/src/infinite-query-options.ts:248](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L248)
+Defined in: [packages/angular-query/src/infinite-query-options.ts:248](https://github.com/TanStack/query/blob/main/packages/angular-query/src/infinite-query-options.ts#L248)
You can generally pass everything to `infiniteQueryOptions` that you can also pass to
`injectInfiniteQuery`. These options can be shared across functions and imperative APIs such as
@@ -179,7 +179,7 @@ automatically as the user scrolls.
A parameterized factory, so the same options object can be reused per `postId`:
```angular-ts
-import { infiniteQueryOptions, injectInfiniteQuery } from '@tanstack/angular-query-experimental'
+import { infiniteQueryOptions, injectInfiniteQuery } from '@tanstack/angular-query'
export const commentsOptions = (postId: string) =>
infiniteQueryOptions({
@@ -221,7 +221,7 @@ export class Comments {
function infiniteQueryOptions, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(options: UndefinedInitialDataInfiniteOptions): UndefinedInitialDataInfiniteOptions & QueryKeyWithDataTag, TError>;
```
-Defined in: [packages/angular-query-experimental/src/infinite-query-options.ts:319](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L319)
+Defined in: [packages/angular-query/src/infinite-query-options.ts:319](https://github.com/TanStack/query/blob/main/packages/angular-query/src/infinite-query-options.ts#L319)
You can generally pass everything to `infiniteQueryOptions` that you can also pass to
`injectInfiniteQuery`. These options can be shared across functions and imperative APIs such as
@@ -278,7 +278,7 @@ automatically as the user scrolls) and that use `skipToken` to disable the query
A parameterized factory, so the same options object can be reused per `postId`:
```angular-ts
-import { infiniteQueryOptions, injectInfiniteQuery } from '@tanstack/angular-query-experimental'
+import { infiniteQueryOptions, injectInfiniteQuery } from '@tanstack/angular-query'
export const commentsOptions = (postId: string) =>
infiniteQueryOptions({
diff --git a/docs/framework/angular/reference/functions/injectInfiniteQuery.md b/docs/framework/angular/reference/functions/injectInfiniteQuery.md
index 1916a7ebc20..a7ecafdd6ab 100644
--- a/docs/framework/angular/reference/functions/injectInfiniteQuery.md
+++ b/docs/framework/angular/reference/functions/injectInfiniteQuery.md
@@ -8,14 +8,14 @@ title: injectInfiniteQuery
## Overview
```ts
-function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(injectInfiniteQueryFn: () => DefinedInitialDataInfiniteOptions, options?: InjectInfiniteQueryOptions): DefinedCreateInfiniteQueryResult;
-function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(injectInfiniteQueryFn: () => UndefinedInitialDataInfiniteOptions, options?: InjectInfiniteQueryOptions): CreateInfiniteQueryResult;
-function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(injectInfiniteQueryFn: () => CreateInfiniteQueryOptions, options?: InjectInfiniteQueryOptions): CreateInfiniteQueryResult;
+function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(optionsFn: () => DefinedInitialDataInfiniteOptions): DefinedCreateInfiniteQueryResult;
+function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(optionsFn: () => UndefinedInitialDataInfiniteOptions): CreateInfiniteQueryResult;
+function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(optionsFn: () => CreateInfiniteQueryOptions): CreateInfiniteQueryResult;
```
-- [`() => DefinedInitialDataInfiniteOptions` → `DefinedCreateInfiniteQueryResult`](#call-signature-1): The options for `injectInfiniteQuery` are identical to `injectQuery`, with the addition of `initialPageParam`, `getNextPageParam`, `getPreviousPageParam`, and `maxPages`. Infinite queries can additively "load more" data onto an existing set of data, or "infinite scroll".
-- [`() => UndefinedInitialDataInfiniteOptions` → `CreateInfiniteQueryResult`](#call-signature-2): Injects an infinite query: a declarative dependency on an asynchronous source of data that is tied to a unique key. Infinite queries can additively "load more" data onto an existing set of data, or "infinite scroll".
-- [`() => CreateInfiniteQueryOptions` → `CreateInfiniteQueryResult`](#call-signature-3): This overload accepts the general [CreateInfiniteQueryOptions](../interfaces/CreateInfiniteQueryOptions.md) shape rather than the `initialData`-aware overloads above, so whether `data` is defined can't be inferred from the call site — useful when wrapping `injectInfiniteQuery` in your own helper function that forwards caller-provided options.
+- [`() => DefinedInitialDataInfiniteOptions` → `DefinedCreateInfiniteQueryResult`](#call-signature-1): This overload is selected when `initialData` is set, so the resulting `data` signal is never `undefined` (unless a `select` changes `TData` to include `undefined`).
+- [`() => UndefinedInitialDataInfiniteOptions` → `CreateInfiniteQueryResult`](#call-signature-2): Injects an infinite query: a declarative dependency on an asynchronous source of data that is tied to a unique key. Infinite queries can additively "load more" data onto an existing set of data or support infinite scroll.
+- [`() => CreateInfiniteQueryOptions` → `CreateInfiniteQueryResult`](#call-signature-3): This overload accepts the general [CreateInfiniteQueryOptions](../interfaces/CreateInfiniteQueryOptions.md) shape rather than the `initialData`-aware overloads above, so whether `data` is defined can't be inferred from the call site — useful when wrapping `injectInfiniteQuery` in your own helper.
See also: [Parameters](#parameters-summary) · [Returns](#returns-summary)
@@ -24,18 +24,13 @@ See also: [Parameters](#parameters-summary) · [Returns](#returns-summary)
## Call Signature
```ts
-function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(injectInfiniteQueryFn: () => DefinedInitialDataInfiniteOptions, options?: InjectInfiniteQueryOptions): DefinedCreateInfiniteQueryResult;
+function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(optionsFn: () => DefinedInitialDataInfiniteOptions): DefinedCreateInfiniteQueryResult;
```
-Defined in: [packages/angular-query-experimental/src/inject-infinite-query.ts:87](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L87)
+Defined in: [packages/angular-query/src/inject-infinite-query.ts:38](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-infinite-query.ts#L38)
-The options for `injectInfiniteQuery` are identical to `injectQuery`, with the addition of
-`initialPageParam`, `getNextPageParam`, `getPreviousPageParam`, and `maxPages`. Infinite queries can
-additively "load more" data onto an existing set of data, or "infinite scroll".
-
-This overload is selected when `initialData` is known to be defined on the options returned by
-`injectInfiniteQueryFn`, so the resulting `data` signal is never `undefined` (unless a `select` changes
-`TData` to include `undefined`).
+This overload is selected when `initialData` is set, so the resulting `data` signal is never `undefined`
+(unless a `select` changes `TData` to include `undefined`).
### Type Parameters
@@ -61,82 +56,37 @@ This overload is selected when `initialData` is known to be defined on the optio
### Parameters
-#### injectInfiniteQueryFn
+#### optionsFn
() => [`DefinedInitialDataInfiniteOptions`](../type-aliases/DefinedInitialDataInfiniteOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
-A function returning the [DefinedInitialDataInfiniteOptions](../type-aliases/DefinedInitialDataInfiniteOptions.md) to use —
-everything you can pass to `injectInfiniteQuery`, with `initialData` known to be defined. Similar to
-`computed` from Angular, this function runs in the reactive context, so signals read inside it drive the
-query.
-
-#### options?
-
-[`InjectInfiniteQueryOptions`](../interfaces/InjectInfiniteQueryOptions.md)
-
-Additional configuration.
+A function returning infinite-query options with `initialData` set. Similar to
+`computed` from Angular, this function runs in the reactive context.
### Returns
[`DefinedCreateInfiniteQueryResult`](../type-aliases/DefinedCreateInfiniteQueryResult.md)\<`TData`, `TError`\>
-The same signals as `injectQuery`, with the addition of `fetchNextPage`, `fetchPreviousPage`,
-`hasNextPage`, `hasPreviousPage`, `isFetchingNextPage`, and `isFetchingPreviousPage`. `data().pages` and
-`data().pageParams` are also added, as long as a `select` doesn't change `TData` away from its default
-`InfiniteData` shape.
-
-### Remarks
-
-Keep in mind that imperative fetch calls, such as `fetchNextPage`, may interfere with the default
-refetch behavior, resulting in outdated data. Make sure to call these functions only in response to user
-actions, or add conditions like `hasNextPage() && !isFetching()`.
+The infinite query result, typed so that `data` is never `undefined`.
### See
-[infiniteQueryOptions](infiniteQueryOptions.md) to share these options between `injectInfiniteQuery` and imperative APIs
-like `queryClient.fetchInfiniteQuery`.
-
-### Example
-
-```angular-ts
-@Component({
- selector: 'projects',
- template: `
-
-
- @for (page of projectsQuery.data().pages; track $index) {
- @for (project of page.projects; track project.id) {
-
{{ project.name }}
- }
- }
-
- `,
-})
-export class Projects {
- readonly projectsQuery = injectInfiniteQuery(() => ({
- queryKey: ['projects'],
- queryFn: ({ pageParam }) => fetchProjects(pageParam),
- initialPageParam: 0,
- getNextPageParam: (lastPage) => lastPage.nextId,
- initialData: { pages: [], pageParams: [] },
- }))
-}
-```
+ - https://tanstack.com/query/latest/docs/framework/angular/guides/infinite-queries
+ - [infiniteQueryOptions](infiniteQueryOptions.md) to share these options between `injectInfiniteQuery` and
+`queryClient.infiniteQuery`.
## Call Signature
```ts
-function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(injectInfiniteQueryFn: () => UndefinedInitialDataInfiniteOptions, options?: InjectInfiniteQueryOptions): CreateInfiniteQueryResult;
+function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(optionsFn: () => UndefinedInitialDataInfiniteOptions): CreateInfiniteQueryResult;
```
-Defined in: [packages/angular-query-experimental/src/inject-infinite-query.ts:239](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L239)
+Defined in: [packages/angular-query/src/inject-infinite-query.ts:92](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-infinite-query.ts#L92)
-Injects an infinite query: a declarative dependency on an asynchronous source of data that is tied to a
-unique key. Infinite queries can additively "load more" data onto an existing set of data, or
-"infinite scroll".
+Injects an infinite query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
+Infinite queries can additively "load more" data onto an existing set of data or support infinite scroll.
### Type Parameters
@@ -162,155 +112,51 @@ unique key. Infinite queries can additively "load more" data onto an existing se
### Parameters
-#### injectInfiniteQueryFn
+#### optionsFn
() => [`UndefinedInitialDataInfiniteOptions`](../type-aliases/UndefinedInitialDataInfiniteOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
-A function returning the [UndefinedInitialDataInfiniteOptions](../type-aliases/UndefinedInitialDataInfiniteOptions.md) to use
-— everything you can pass to `injectInfiniteQuery`. Similar to `computed` from Angular, this function runs
-in the reactive context, so signals read inside it drive the query.
-
-#### options?
-
-[`InjectInfiniteQueryOptions`](../interfaces/InjectInfiniteQueryOptions.md)
-
-Additional configuration.
+A function that returns infinite query options. Similar to `computed` from Angular,
+this function runs in the reactive context, so signals read inside it drive the query.
### Returns
[`CreateInfiniteQueryResult`](../type-aliases/CreateInfiniteQueryResult.md)\<`TData`, `TError`\>
-The same signals as `injectQuery`, with the addition of `fetchNextPage`, `fetchPreviousPage`,
-`hasNextPage`, `hasPreviousPage`, `isFetchingNextPage`, and `isFetchingPreviousPage`. `data().pages` and
-`data().pageParams` are also added, as long as a `select` doesn't change `TData` away from its default
-`InfiniteData` shape.
-
-### Remarks
-
-Keep in mind that imperative fetch calls, such as `fetchNextPage`, may interfere with the default
-refetch behavior, resulting in outdated data. Make sure to call these functions only in response to user
-actions, or add conditions like `hasNextPage() && !isFetching()`. This is the only overload that accepts
-`queryFn: skipToken`, shown below.
+The infinite query result.
### See
-[infiniteQueryOptions](infiniteQueryOptions.md) to share these options between `injectInfiniteQuery` and imperative APIs
-like `queryClient.fetchInfiniteQuery`.
-
-### Examples
-
-Fetching the next page from a button click:
-```angular-ts
-@Component({
- selector: 'projects-list',
- template: `
-
- @for (page of projectsQuery.data()?.pages; track $index) {
- @for (project of page.projects; track project.id) {
-
{{ project.name }}
- }
- }
-
-
- `,
-})
-export class ProjectsList {
- readonly projectsQuery = injectInfiniteQuery(() => ({
- queryKey: ['projects'],
- queryFn: ({ pageParam }) => fetchProjects(pageParam),
- initialPageParam: 0,
- getNextPageParam: (lastPage) => lastPage.nextId,
- }))
-}
-```
-
-Fetching the next page automatically as the user scrolls, using an `IntersectionObserver` on a sentinel
-element after the list:
-```angular-ts
-@Component({
- selector: 'projects-list',
- template: `
-
- @for (page of projectsQuery.data()?.pages; track $index) {
- @for (project of page.projects; track project.id) {
-
- `,
-})
-export class ProjectsList {
- readonly sentinel = viewChild>('sentinel')
-
- readonly projectsQuery = injectInfiniteQuery(() => ({
- queryKey: ['projects'],
- queryFn: ({ pageParam }) => fetchProjects(pageParam),
- initialPageParam: 0,
- getNextPageParam: (lastPage) => lastPage.nextId,
- }))
+ - https://tanstack.com/query/latest/docs/framework/angular/guides/infinite-queries
+ - [infiniteQueryOptions](infiniteQueryOptions.md) to share these options between `injectInfiniteQuery` and
+`queryClient.infiniteQuery`.
- constructor() {
- effect((onCleanup) => {
- const sentinel = this.sentinel()?.nativeElement
- if (
- sentinel == null ||
- !this.projectsQuery.hasNextPage() ||
- this.projectsQuery.isFetching()
- ) {
- return
- }
-
- const observer = new IntersectionObserver(([entry]) => {
- if (entry?.isIntersecting) this.projectsQuery.fetchNextPage()
- })
- observer.observe(sentinel)
-
- onCleanup(() => observer.disconnect())
- })
- }
-}
-```
+### Example
-A query that's disabled, type safe, until `postId` is set — pass `skipToken` as `queryFn` instead of
-setting `enabled: false`:
```angular-ts
@Component({
- selector: 'comments',
+ selector: 'projects',
template: `
- @if (postId() == null) {
- Select a post
- } @else if (commentsQuery.isPending()) {
+ @if (query.isPending()) {
Loading...
- } @else if (commentsQuery.isError()) {
- Error: {{ commentsQuery.error()?.message }}
+ } @else if (query.isError()) {
+ Error: {{ query.error()?.message }}
} @else {
-
- @for (page of commentsQuery.data().pages; track $index) {
- @for (comment of page.comments; track comment.id) {
-
{{ comment.text }}
- }
+ @for (page of query.data().pages; track $index) {
+ @for (project of page; track project.id) {
+
{{ project.name }}
}
-
+ }
+
}
`,
})
-export class Comments {
- readonly postId = signal(undefined)
-
- readonly commentsQuery = injectInfiniteQuery(() => ({
- queryKey: ['post', this.postId(), 'comments'],
- queryFn:
- this.postId() != null
- ? ({ pageParam }) => fetchComments(this.postId()!, pageParam)
- : skipToken,
+export class Projects {
+ readonly query = injectInfiniteQuery(() => ({
+ queryKey: ['projects'],
+ queryFn: ({ pageParam }) => fetchProjects(pageParam),
initialPageParam: 0,
- getNextPageParam: (lastPage) => lastPage.nextId,
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
}))
}
```
@@ -320,15 +166,14 @@ export class Comments {
## Call Signature
```ts
-function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(injectInfiniteQueryFn: () => CreateInfiniteQueryOptions, options?: InjectInfiniteQueryOptions): CreateInfiniteQueryResult;
+function injectInfiniteQuery, TQueryKey extends readonly unknown[] = readonly unknown[], TPageParam = unknown>(optionsFn: () => CreateInfiniteQueryOptions): CreateInfiniteQueryResult;
```
-Defined in: [packages/angular-query-experimental/src/inject-infinite-query.ts:266](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L266)
+Defined in: [packages/angular-query/src/inject-infinite-query.ts:117](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-infinite-query.ts#L117)
This overload accepts the general [CreateInfiniteQueryOptions](../interfaces/CreateInfiniteQueryOptions.md) shape rather than the
-`initialData`-aware overloads above, so whether `data` is defined can't be inferred from the call site —
-useful when wrapping `injectInfiniteQuery` in your own helper function that forwards caller-provided
-options.
+`initialData`-aware overloads above, so whether `data` is defined can't be inferred from the call
+site — useful when wrapping `injectInfiniteQuery` in your own helper.
### Type Parameters
@@ -354,18 +199,12 @@ options.
### Parameters
-#### injectInfiniteQueryFn
+#### optionsFn
() => [`CreateInfiniteQueryOptions`](../interfaces/CreateInfiniteQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
-A function that returns infinite query options. Similar to `computed` from
-Angular, this function runs in the reactive context, so signals read inside it drive the query.
-
-#### options?
-
-[`InjectInfiniteQueryOptions`](../interfaces/InjectInfiniteQueryOptions.md)
-
-Additional configuration.
+A function that returns infinite query options. Similar to `computed` from Angular,
+this function runs in the reactive context, so signals read inside it drive the query.
### Returns
@@ -373,66 +212,54 @@ Additional configuration.
The infinite query result.
+### See
+
+https://tanstack.com/query/latest/docs/framework/angular/guides/infinite-queries
+
## Parameters
-### injectInfiniteQueryFn
+### optionsFn
() => [`CreateInfiniteQueryOptions`](../interfaces/CreateInfiniteQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
-A function that returns infinite query options. Similar to `computed` from
-Angular, this function runs in the reactive context, so signals read inside it drive the query.
+A function that returns infinite query options. Similar to `computed` from Angular,
+this function runs in the reactive context, so signals read inside it drive the query.
-
+
-#### `injectInfiniteQueryFn` properties
+#### `optionsFn` properties
| Property | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
-| `enabled?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean`) | `true` | Set this to `false` or a function that returns `false` to disable automatic refetching when the query mounts or changes query keys. To refetch the query, use the `refetch` method returned from the `useQuery` instance. Accepts a boolean or function that returns a boolean. |
-| `gcTime?` | `number` | `undefined` | The time in milliseconds that unused/inactive cache data remains in memory. When a query's cache becomes unused or inactive, that cache data will be garbage collected after this duration. When different garbage collection times are specified, the longest one will be used. Setting it to `Infinity` will disable garbage collection. Defaults to `5 * 60 * 1000` (5 minutes), or `Infinity` during SSR. Note: the maximum allowed time is about 24 days, imposed by `setTimeout`'s 32-bit signed integer delay — see `timeoutManager.setTimeoutProvider` for a workaround. |
-| `getNextPageParam` | (`lastPage`: `TQueryFnData`, `allPages`: `TQueryFnData`[], `lastPageParam`: `TPageParam`, `allPageParams`: `TPageParam`[]) => `TPageParam` \| `null` \| `undefined` | `undefined` | This function can be set to automatically get the next cursor for infinite queries. The result will also be used to determine the value of `hasNextPage`. |
-| `getPreviousPageParam?` | (`firstPage`: `TQueryFnData`, `allPages`: `TQueryFnData`[], `firstPageParam`: `TPageParam`, `allPageParams`: `TPageParam`[]) => `TPageParam` \| `null` \| `undefined` | `undefined` | This function can be set to automatically get the previous cursor for infinite queries. The result will also be used to determine the value of `hasPreviousPage`. |
-| `initialData?` | \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| (() => \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| `undefined`) | `undefined` | If set, this value will be used as the initial data for the query cache (as long as the query hasn't been created or cached yet). If set to a function, the function will be called **once** during the shared/root query initialization, and be expected to synchronously return the initial data. Initial data is considered stale by default unless a `staleTime` has been set. `initialData` **is persisted** to the cache. |
-| `initialDataUpdatedAt?` | `number` \| (() => `number` \| `undefined`) | `undefined` | If set, this value will be used as the time (in milliseconds) of when the `initialData` itself was last updated. |
-| `initialPageParam` | `TPageParam` | `undefined` | The page param to start from when an infinite query has no pages yet. It is passed to `queryFn` as `pageParam` for the first page; every page after that gets the value returned by `getNextPageParam` or `getPreviousPageParam`. It only applies while the query has no pages: once a first page exists, refetching starts from that page's own param instead. |
-| `maxPages?` | `number` | `undefined` | Maximum number of pages to store in the data of an infinite query. |
-| `meta?` | `Record`\<`string`, `unknown`\> | `undefined` | Additional payload to be stored on each query. Use this property to pass information that can be used in other places. |
-| `networkMode?` | `"online"` \| `"always"` \| `"offlineFirst"` | `'online'` | Controls whether a query is allowed to run based on the current network connectivity. **See** [Network Mode](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode) for more information. |
-| `notifyOnChangeProps?` | \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `"all"` \| (() => \| `"all"` \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `undefined`) | `undefined` | If set, the component will only re-render if any of the listed properties change. When set to `['data', 'error']`, the component will only re-render when the `data` or `error` properties change. When set to `'all'`, the component will re-render whenever a query is updated. When set to a function, the function will be executed to compute the list of properties. Defaults to `undefined`, in which case property access is tracked automatically, and the component only re-renders when one of the tracked properties changes. |
-| `persister?` | (`queryFn`: (`context`: [`QueryFunctionContext`](../type-aliases/QueryFunctionContext.md)\<`NoInfer`\<`TQueryKey`\>, `TPageParam`\>) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>, `context`: `object`, `query`: [`Query`](../classes/Query.md)) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\> | `undefined` | This option can be used to persist the result of a query to an external storage, bypassing the need to actually call the `queryFn`. Useful for persisting a query's data across e.g. server/client boundaries. |
-| `placeholderData?` | \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| ((`previousData`: \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| `undefined`, `previousQuery`: \| [`Query`](../classes/Query.md)\<[`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\> \| `undefined`) => \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| `undefined`) | `undefined` | If set, this value will be used as the placeholder data for this particular query observer while the query is still in the `loading` data and no initialData has been provided. |
-| `queryFn?` | \| *typeof* [`skipToken`](../variables/skipToken.md) \| ((`context`: [`QueryFunctionContext`](../type-aliases/QueryFunctionContext.md)\<`TQueryKey`, `TPageParam`\>) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>) | `undefined` | The function that the query will use to request data. Required, unless a default query function has been set via `queryClient.setQueryDefaults` or `queryClient.setDefaultOptions`. Receives a [QueryFunctionContext](../type-aliases/QueryFunctionContext.md). Must return a promise that will either resolve data or throw an error. The data cannot be `undefined`. |
-| `queryHash?` | `string` | `undefined` | The hashed form of `queryKey`, computed with `queryKeyHashFn` (or the default hashing function otherwise). Used as the actual cache key internally. |
-| `queryKey` | `TQueryKey` & `object` | `undefined` | The query key to use for this query. The query key will be hashed into a stable hash. See [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for more information. The query will automatically update when this key changes (as long as `enabled` is not set to `false`). |
-| `queryKeyHashFn?` | (`queryKey`: `TQueryKey`) => `string` | `undefined` | If specified, this function is used to hash the `queryKey` to a string. |
-| `refetchInterval?` | \| `number` \| `false` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `number` \| `false` \| `undefined`) | `false` | If set to a number, the query will continuously refetch at this frequency in milliseconds. If set to a function, the function will be executed with the latest data and query to compute a frequency |
-| `refetchIntervalInBackground?` | `boolean` | `false` | If set to `true`, the query will continue to refetch while their tab/window is in the background. |
-| `refetchOnMount?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on mount if the data is stale. If set to `false`, will disable additional instances of a query to trigger background refetch. If set to `'always'`, the query will always refetch on mount (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value |
-| `refetchOnReconnect?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean` \| `"always"`) | `undefined` | If set to `true`, the query will refetch on reconnect if the data is stale. If set to `false`, the query will not refetch on reconnect. If set to `'always'`, the query will always refetch on reconnect (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. Defaults to `true` unless `networkMode` is `'always'`. |
-| `refetchOnWindowFocus?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on window focus if the data is stale. If set to `false`, the query will not refetch on window focus. If set to `'always'`, the query will always refetch on window focus (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. |
-| `retry?` | \| `number` \| `false` \| `true` \| ((`failureCount`: `number`, `error`: `TError`) => `boolean`) | `undefined` | If `false`, failed queries will not retry by default. If `true`, failed queries will retry infinitely. If set to an integer number, e.g. 3, failed queries will retry until the failed query count meets that number. If set to a function `(failureCount, error) => boolean` failed queries will retry until the function returns false. Defaults to `3` on the client and `0` on the server. |
-| `retryDelay?` | `number` \| ((`failureCount`: `number`, `error`: `TError`) => `number`) | `undefined` | This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff. A function like `attempt => attempt * 1000` applies linear backoff. Defaults to a function that applies exponential backoff, capped at 30 seconds. |
-| `retryOnMount?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean`) | `true` | If set to `false`, the query will not be retried on mount if it contains an error. If set to a function, the function will be executed with the query to compute the value. |
-| `select?` | (`data`: [`InfiniteData`](../interfaces/InfiniteData.md)) => `TData` | `undefined` | This option can be used to transform or select a part of the data returned by the query function. It affects the returned `data` value, but does not affect what gets stored in the query cache. The `select` function will only run if `data` changed, or if the reference to the `select` function itself changes. To optimize, memoize the function so its reference stays stable across calls. |
-| `staleTime?` | \| `number` \| `"static"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `number` \| `"static"`) | `0` | The time in milliseconds after data is considered stale. If set to `Infinity`, the data will never be considered stale. If set to `'static'`, the data will never be considered stale. If set to a function, the function will be executed with the query to compute a `staleTime`. |
-| `structuralSharing?` | `boolean` \| ((`oldData`: `unknown`, `newData`: `unknown`) => `unknown`) | `true` | Set this to `false` to disable structural sharing between query results. Set this to a function which accepts the old and new data and returns resolved data of the same type to implement custom structural sharing logic. |
-| `throwOnError?` | \| `false` \| `true` \| ((`error`: `TError`, `query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean`) | `false` | Whether errors should be thrown instead of setting the `error` property. If set to `true` or `suspense` is `true`, all errors will be thrown to the error boundary. If set to `false` and `suspense` is `false`, errors are returned as state. If set to a function, it will be passed the error and the query, and it should return a boolean indicating whether to show the error in an error boundary (`true`) or return the error as state (`false`). |
-
-### options?
-
-[`InjectInfiniteQueryOptions`](../interfaces/InjectInfiniteQueryOptions.md)
-
-Additional configuration.
-
-
-
-#### `options` properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the infinite query. If this is not provided, the current injection context will be used instead (via `inject`). |
+| `enabled?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean`) | `true` | Set this to `false` or a function that returns `false` to disable automatic refetching when the query mounts or changes query keys. To refetch the query, use the `refetch` method returned from the `useQuery` instance. Accepts a boolean or function that returns a boolean. |
+| `gcTime?` | `number` | `undefined` | The time in milliseconds that unused/inactive cache data remains in memory. When a query's cache becomes unused or inactive, that cache data will be garbage collected after this duration. When different garbage collection times are specified, the longest one will be used. Setting it to `Infinity` will disable garbage collection. Defaults to `5 * 60 * 1000` (5 minutes), or `Infinity` during SSR. Note: the maximum allowed time is about 24 days, imposed by `setTimeout`'s 32-bit signed integer delay — see `timeoutManager.setTimeoutProvider` for a workaround. |
+| `getNextPageParam` | (`lastPage`: `TQueryFnData`, `allPages`: `TQueryFnData`[], `lastPageParam`: `TPageParam`, `allPageParams`: `TPageParam`[]) => `TPageParam` \| `null` \| `undefined` | `undefined` | This function can be set to automatically get the next cursor for infinite queries. The result will also be used to determine the value of `hasNextPage`. |
+| `getPreviousPageParam?` | (`firstPage`: `TQueryFnData`, `allPages`: `TQueryFnData`[], `firstPageParam`: `TPageParam`, `allPageParams`: `TPageParam`[]) => `TPageParam` \| `null` \| `undefined` | `undefined` | This function can be set to automatically get the previous cursor for infinite queries. The result will also be used to determine the value of `hasPreviousPage`. |
+| `initialData?` | \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| (() => \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| `undefined`) | `undefined` | If set, this value will be used as the initial data for the query cache (as long as the query hasn't been created or cached yet). If set to a function, the function will be called **once** during the shared/root query initialization, and be expected to synchronously return the initial data. Initial data is considered stale by default unless a `staleTime` has been set. `initialData` **is persisted** to the cache. |
+| `initialDataUpdatedAt?` | `number` \| (() => `number` \| `undefined`) | `undefined` | If set, this value will be used as the time (in milliseconds) of when the `initialData` itself was last updated. |
+| `initialPageParam` | `TPageParam` | `undefined` | The page param to start from when an infinite query has no pages yet. It is passed to `queryFn` as `pageParam` for the first page; every page after that gets the value returned by `getNextPageParam` or `getPreviousPageParam`. It only applies while the query has no pages: once a first page exists, refetching starts from that page's own param instead. |
+| `maxPages?` | `number` | `undefined` | Maximum number of pages to store in the data of an infinite query. |
+| `meta?` | `Record`\<`string`, `unknown`\> | `undefined` | Additional payload to be stored on each query. Use this property to pass information that can be used in other places. |
+| `networkMode?` | `"online"` \| `"always"` \| `"offlineFirst"` | `'online'` | Controls whether a query is allowed to run based on the current network connectivity. **See** [Network Mode](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode) for more information. |
+| `persister?` | (`queryFn`: (`context`: [`QueryFunctionContext`](../type-aliases/QueryFunctionContext.md)\<`NoInfer`\<`TQueryKey`\>, `TPageParam`\>) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>, `context`: `object`, `query`: [`Query`](../classes/Query.md)) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\> | `undefined` | This option can be used to persist the result of a query to an external storage, bypassing the need to actually call the `queryFn`. Useful for persisting a query's data across e.g. server/client boundaries. |
+| `placeholderData?` | \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| ((`previousData`: \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| `undefined`, `previousQuery`: \| [`Query`](../classes/Query.md)\<[`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\> \| `undefined`) => \| [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| `undefined`) | `undefined` | If set, this value will be used as the placeholder data for this particular query observer while the query is still in the `loading` data and no initialData has been provided. |
+| `queryFn?` | \| *typeof* [`skipToken`](../variables/skipToken.md) \| ((`context`: [`QueryFunctionContext`](../type-aliases/QueryFunctionContext.md)\<`TQueryKey`, `TPageParam`\>) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>) | `undefined` | The function that the query will use to request data. Required, unless a default query function has been set via `queryClient.setQueryDefaults` or `queryClient.setDefaultOptions`. Receives a [QueryFunctionContext](../type-aliases/QueryFunctionContext.md). Must return a promise that will either resolve data or throw an error. The data cannot be `undefined`. |
+| `queryHash?` | `string` | `undefined` | The hashed form of `queryKey`, computed with `queryKeyHashFn` (or the default hashing function otherwise). Used as the actual cache key internally. |
+| `queryKey` | `TQueryKey` & `object` | `undefined` | The query key to use for this query. The query key will be hashed into a stable hash. See [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for more information. The query will automatically update when this key changes (as long as `enabled` is not set to `false`). |
+| `queryKeyHashFn?` | (`queryKey`: `TQueryKey`) => `string` | `undefined` | If specified, this function is used to hash the `queryKey` to a string. |
+| `refetchInterval?` | \| `number` \| `false` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `number` \| `false` \| `undefined`) | `false` | If set to a number, the query will continuously refetch at this frequency in milliseconds. If set to a function, the function will be executed with the latest data and query to compute a frequency |
+| `refetchIntervalInBackground?` | `boolean` | `false` | If set to `true`, the query will continue to refetch while their tab/window is in the background. |
+| `refetchOnMount?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on mount if the data is stale. If set to `false`, will disable additional instances of a query to trigger background refetch. If set to `'always'`, the query will always refetch on mount (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value |
+| `refetchOnReconnect?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean` \| `"always"`) | `undefined` | If set to `true`, the query will refetch on reconnect if the data is stale. If set to `false`, the query will not refetch on reconnect. If set to `'always'`, the query will always refetch on reconnect (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. Defaults to `true` unless `networkMode` is `'always'`. |
+| `refetchOnWindowFocus?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on window focus if the data is stale. If set to `false`, the query will not refetch on window focus. If set to `'always'`, the query will always refetch on window focus (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. |
+| `retry?` | \| `number` \| `false` \| `true` \| ((`failureCount`: `number`, `error`: `TError`) => `boolean`) | `undefined` | If `false`, failed queries will not retry by default. If `true`, failed queries will retry infinitely. If set to an integer number, e.g. 3, failed queries will retry until the failed query count meets that number. If set to a function `(failureCount, error) => boolean` failed queries will retry until the function returns false. Defaults to `3` on the client and `0` on the server. |
+| `retryDelay?` | `number` \| ((`failureCount`: `number`, `error`: `TError`) => `number`) | `undefined` | This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff. A function like `attempt => attempt * 1000` applies linear backoff. Defaults to a function that applies exponential backoff, capped at 30 seconds. |
+| `retryOnMount?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean`) | `true` | If set to `false`, the query will not be retried on mount if it contains an error. If set to a function, the function will be executed with the query to compute the value. |
+| `select?` | (`data`: [`InfiniteData`](../interfaces/InfiniteData.md)) => `TData` | `undefined` | This option can be used to transform or select a part of the data returned by the query function. It affects the returned `data` value, but does not affect what gets stored in the query cache. The `select` function will only run if `data` changed, or if the reference to the `select` function itself changes. To optimize, memoize the function so its reference stays stable across calls. |
+| `staleTime?` | \| `number` \| `"static"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](../interfaces/InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `number` \| `"static"`) | `0` | The time in milliseconds after data is considered stale. If set to `Infinity`, the data will never be considered stale. If set to `'static'`, the data will never be considered stale. If set to a function, the function will be executed with the query to compute a `staleTime`. |
+| `structuralSharing?` | `boolean` \| ((`oldData`: `unknown`, `newData`: `unknown`) => `unknown`) | `true` | Set this to `false` to disable structural sharing between query results. Set this to a function which accepts the old and new data and returns resolved data of the same type to implement custom structural sharing logic. |
@@ -441,9 +268,3 @@ Additional configuration.
[`CreateInfiniteQueryResult`](../type-aliases/CreateInfiniteQueryResult.md)\<`TData`, `TError`\>
The infinite query result.
-
-
-
-### Result properties
-
-Built from [`BaseQueryNarrowing`](../interfaces/BaseQueryNarrowing.md#properties), [`InfiniteQueryObserverBaseResult`](../interfaces/InfiniteQueryObserverBaseResult.md#properties). See the type above for what it changes.
diff --git a/docs/framework/angular/reference/functions/injectIsFetching.md b/docs/framework/angular/reference/functions/injectIsFetching.md
index e5f24ac5cb9..a3b6f67d479 100644
--- a/docs/framework/angular/reference/functions/injectIsFetching.md
+++ b/docs/framework/angular/reference/functions/injectIsFetching.md
@@ -6,21 +6,23 @@ title: injectIsFetching
```ts
-function injectIsFetching(filters?: Omit, "fetchStatus">, options?: InjectIsFetchingOptions): Signal;
+function injectIsFetching(filters?: () => Omit): Signal;
```
-Defined in: [packages/angular-query-experimental/src/inject-is-fetching.ts:63](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-fetching.ts#L63)
+Defined in: [packages/angular-query/src/inject-is-fetching.ts:15](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-is-fetching.ts#L15)
Injects a signal that tracks the number of queries that your application is loading or fetching in the
background (useful for app-wide loading indicators).
+Can be used for app-wide loading indicators.
+
## Parameters
### filters?
-`Omit`\<[`QueryFilters`](../interfaces/QueryFilters.md)\, `"fetchStatus"`\>
+() => `Omit`\<[`QueryFilters`](../interfaces/QueryFilters.md), `"fetchStatus"`\>
-The [QueryFilters](../interfaces/QueryFilters.md) to narrow down the matched queries.
+A reactive factory for the filters.
@@ -28,55 +30,8 @@ The [QueryFilters](../interfaces/QueryFilters.md) to narrow down the matched que
Built from [`QueryFilters`](../interfaces/QueryFilters.md#properties). See the type above for what it changes.
-### options?
-
-[`InjectIsFetchingOptions`](../interfaces/InjectIsFetchingOptions.md)
-
-Additional configuration
-
-
-
-#### `options` properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the isFetching signal. If this is not provided, the current injection context will be used instead (via `inject`). |
-
## Returns
`Signal`\<`number`\>
-A `Signal` with the number of queries that your application is currently loading or fetching in
-the background.
-
-## Examples
-
-```angular-ts
-@Component({
- selector: 'posts-fetching-indicator',
- template: `
- @if (isFetchingPosts()) {
- Refreshing posts...
- }
- `,
-})
-export class PostsFetchingIndicator {
- // How many queries matching the posts prefix are fetching?
- readonly isFetchingPosts = injectIsFetching({ queryKey: ['posts'] })
-}
-```
-
-A global loading indicator for any query fetching in the background, not just the ones on screen:
-```angular-ts
-@Component({
- selector: 'global-loading-indicator',
- template: `
- @if (isFetching()) {
-
Queries are fetching in the background...
- }
- `,
-})
-export class GlobalLoadingIndicator {
- readonly isFetching = injectIsFetching()
-}
-```
+signal with number of loading or fetching queries.
diff --git a/docs/framework/angular/reference/functions/injectIsMutating.md b/docs/framework/angular/reference/functions/injectIsMutating.md
index 960200eae60..4b34de57afc 100644
--- a/docs/framework/angular/reference/functions/injectIsMutating.md
+++ b/docs/framework/angular/reference/functions/injectIsMutating.md
@@ -6,21 +6,23 @@ title: injectIsMutating
```ts
-function injectIsMutating(filters?: Omit, "status">, options?: InjectIsMutatingOptions): Signal;
+function injectIsMutating(filters?: () => Omit): Signal;
```
-Defined in: [packages/angular-query-experimental/src/inject-is-mutating.ts:47](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-mutating.ts#L47)
+Defined in: [packages/angular-query/src/inject-is-mutating.ts:15](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-is-mutating.ts#L15)
Injects a signal that tracks the number of mutations that your application currently has `pending`
(useful for app-wide loading indicators).
+Can be used for app-wide loading indicators.
+
## Parameters
### filters?
-`Omit`\<[`MutationFilters`](../interfaces/MutationFilters.md)\<`unknown`, `Error`, `unknown`, `unknown`\>, `"status"`\>
+() => `Omit`\<[`MutationFilters`](../interfaces/MutationFilters.md), `"status"`\>
-The [MutationFilters](../interfaces/MutationFilters.md) to narrow down the matched mutations.
+A reactive factory for the filters.
@@ -28,39 +30,8 @@ The [MutationFilters](../interfaces/MutationFilters.md) to narrow down the match
Built from [`MutationFilters`](../interfaces/MutationFilters.md#properties). See the type above for what it changes.
-### options?
-
-[`InjectIsMutatingOptions`](../interfaces/InjectIsMutatingOptions.md)
-
-Additional configuration
-
-
-
-#### `options` properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the isMutating signal. If this is not provided, the current injection context will be used instead (via `inject`). |
-
## Returns
`Signal`\<`number`\>
-A `Signal` with the number of mutations that your application currently has `pending`.
-
-## Example
-
-```angular-ts
-@Component({
- selector: 'posts-mutating-indicator',
- template: `
- @if (isMutatingPosts()) {
- Saving posts...
- }
- `,
-})
-export class PostsMutatingIndicator {
- // How many mutations matching the posts prefix are in progress?
- readonly isMutatingPosts = injectIsMutating({ mutationKey: ['posts'] })
-}
-```
+A read-only signal with the number of fetching mutations.
diff --git a/docs/framework/angular/reference/functions/injectIsRestoring.md b/docs/framework/angular/reference/functions/injectIsRestoring.md
index b225be8c414..50457404324 100644
--- a/docs/framework/angular/reference/functions/injectIsRestoring.md
+++ b/docs/framework/angular/reference/functions/injectIsRestoring.md
@@ -6,26 +6,16 @@ title: injectIsRestoring
```ts
-function injectIsRestoring(options?: InjectIsRestoringOptions): Signal;
+function injectIsRestoring(): Signal;
```
-Defined in: [packages/angular-query-experimental/src/inject-is-restoring.ts:35](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-restoring.ts#L35)
+Defined in: [packages/angular-query/src/inject-is-restoring.ts:21](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-is-restoring.ts#L21)
-Injects a signal that tracks whether a restore (e.g. from a persisted client, wired up via
-`provideIsRestoring`) is currently in progress. `injectQuery` and friends also check this internally to
-avoid race conditions between the restore and initializing queries.
-
-## Parameters
-
-### options?
-
-`InjectIsRestoringOptions`
-
-Additional configuration
+Injects a readonly signal that is true while the persistence integration restores
+cached query data. Returns false when no restoration is in progress.
## Returns
`Signal`\<`boolean`\>
-A readonly `Signal` — `true` while a restore is in progress, `false` otherwise (the
-default when no `provideIsRestoring` provider is registered).
+The current restoration state.
diff --git a/docs/framework/angular/reference/functions/injectMutation.md b/docs/framework/angular/reference/functions/injectMutation.md
index 1cc364b85e9..5dbcff7037c 100644
--- a/docs/framework/angular/reference/functions/injectMutation.md
+++ b/docs/framework/angular/reference/functions/injectMutation.md
@@ -6,13 +6,13 @@ title: injectMutation
```ts
-function injectMutation(injectMutationFn: () => CreateMutationOptions, options?: InjectMutationOptions): CreateMutationResult;
+function injectMutation(optionsFn: () => CreateMutationOptions): CreateMutationResult;
```
-Defined in: [packages/angular-query-experimental/src/inject-mutation.ts:172](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L172)
+Defined in: [packages/angular-query/src/inject-mutation.ts:49](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-mutation.ts#L49)
-Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.
-`injectMutation` is the function for that. Unlike queries, mutations are not run automatically.
+Injects a mutation: an imperative function that can be invoked which typically performs server side effects.
+Unlike queries, mutations are not run automatically.
## Type Parameters
@@ -34,181 +34,59 @@ Unlike queries, mutations are typically used to create/update/delete data or per
## Parameters
-### injectMutationFn
+### optionsFn
() => [`CreateMutationOptions`](../interfaces/CreateMutationOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
-A function that returns mutation options. Similar to `computed` from Angular,
-this function runs in the reactive context, so signals read inside it drive the mutation's options.
+A function that returns mutation options. Similar to `computed` from Angular, this
+function runs in the reactive context, so signals read inside it drive the mutation.
-
+
-#### `injectMutationFn` properties
+#### `optionsFn` properties
| Property | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
-| `gcTime?` | `number` | `undefined` | The time in milliseconds that an unused/inactive mutation remains in memory before it is garbage collected. Defaults to `5 * 60 * 1000` (5 minutes), or `Infinity` during SSR. |
-| `meta?` | `Record`\<`string`, `unknown`\> | `undefined` | Additional payload to be stored on the mutation cache entry. Use it to pass information that can be read wherever the `mutation` is available, such as the `onError` and `onSuccess` callbacks of the `MutationCache`. |
-| `mutationFn?` | (`variables`: `TVariables`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `Promise`\<`TData`\> | `undefined` | The function that performs the asynchronous task this mutation runs. Required, unless a default mutation function has been set for the matching `mutationKey` via `queryClient.setMutationDefaults`. Receives the `variables` passed to `mutate`, and a [MutationFunctionContext](../type-aliases/MutationFunctionContext.md) holding the `QueryClient`, the `mutationKey` and `meta`. Must return a promise that resolves the mutation's data. |
-| `mutationKey?` | readonly `unknown`[] | `undefined` | The key to use for this mutation. Optional, but required to inherit defaults registered with `queryClient.setMutationDefaults`, and to match this mutation with `useMutationState` or `queryClient.isMutating`. |
-| `networkMode?` | `"online"` \| `"always"` \| `"offlineFirst"` | `'online'` | Controls whether a mutation is allowed to run based on the current network connectivity. **See** [Network Mode](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode) for more information. |
-| `onError?` | (`error`: `TError`, `variables`: `TVariables`, `onMutateResult`: `TOnMutateResult` \| `undefined`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `unknown` | `undefined` | This function fires when the mutation encounters an error, and is passed the error. If a promise is returned, it is awaited before `onSettled` runs. |
-| `onMutate?` | (`variables`: `TVariables`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `TOnMutateResult` \| `Promise`\<`TOnMutateResult`\> | `undefined` | This function fires before the mutation function runs, and receives the same variables. Useful for optimistic updates applied in the hope that the mutation succeeds. The value it returns is passed to `onSuccess`, `onError` and `onSettled` as `onMutateResult`, which is where an optimistic update is usually rolled back. If a promise is returned, it is awaited before the mutation function runs. |
-| `onSettled?` | (`data`: `TData` \| `undefined`, `error`: `TError` \| `null`, `variables`: `TVariables`, `onMutateResult`: `TOnMutateResult` \| `undefined`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `unknown` | `undefined` | This function fires when the mutation either succeeds or errors, and is passed either the data or the error. If a promise is returned, it is awaited before the mutation settles. |
-| `onSuccess?` | (`data`: `TData`, `variables`: `TVariables`, `onMutateResult`: `TOnMutateResult`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `unknown` | `undefined` | This function fires when the mutation succeeds, and is passed the mutation's result. If a promise is returned, it is awaited before `onSettled` runs. |
-| `retry?` | \| `number` \| `false` \| `true` \| ((`failureCount`: `number`, `error`: `TError`) => `boolean`) | `0` | If `false`, failed mutations will not retry by default. If `true`, failed mutations will retry infinitely. If set to an integer number, e.g. 3, failed mutations will retry until the failed mutation count meets that number. If set to a function `(failureCount, error) => boolean` failed mutations will retry until the function returns false. |
-| `retryDelay?` | `number` \| ((`failureCount`: `number`, `error`: `TError`) => `number`) | `undefined` | This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. Defaults to a function that applies exponential backoff, capped at 30 seconds. |
-| `scope?` | [`MutationScope`](../type-aliases/MutationScope.md) | `undefined` | Controls whether this mutation runs alongside others or waits its turn. Mutations sharing the same `scope.id` run serially, in the order they were started. Without a scope, a mutation runs as soon as it is triggered. |
-| `throwOnError?` | `boolean` \| ((`error`: `TError`) => `boolean`) | `false` | Whether errors should be thrown instead of setting the `error` property. If set to `true`, all errors will be thrown to the nearest error boundary. If set to a function, it will be passed the error and should return a boolean indicating whether to throw the error (`true`) or return it as state (`false`). |
-
-### options?
-
-[`InjectMutationOptions`](../interfaces/InjectMutationOptions.md)
-
-Additional configuration
-
-
-
-#### `options` properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the mutation. If this is not provided, the current injection context will be used instead (via `inject`). |
+| `gcTime?` | `number` | `undefined` | The time in milliseconds that an unused/inactive mutation remains in memory before it is garbage collected. Defaults to `5 * 60 * 1000` (5 minutes), or `Infinity` during SSR. |
+| `meta?` | `Record`\<`string`, `unknown`\> | `undefined` | Additional payload to be stored on the mutation cache entry. Use it to pass information that can be read wherever the `mutation` is available, such as the `onError` and `onSuccess` callbacks of the `MutationCache`. |
+| `mutationFn?` | (`variables`: `TVariables`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `Promise`\<`TData`\> | `undefined` | The function that performs the asynchronous task this mutation runs. Required, unless a default mutation function has been set for the matching `mutationKey` via `queryClient.setMutationDefaults`. Receives the `variables` passed to `mutate`, and a [MutationFunctionContext](../type-aliases/MutationFunctionContext.md) holding the `QueryClient`, the `mutationKey` and `meta`. Must return a promise that resolves the mutation's data. |
+| `mutationKey?` | readonly `unknown`[] | `undefined` | The key to use for this mutation. Optional, but required to inherit defaults registered with `queryClient.setMutationDefaults`, and to match this mutation with `useMutationState` or `queryClient.isMutating`. |
+| `networkMode?` | `"online"` \| `"always"` \| `"offlineFirst"` | `'online'` | Controls whether a mutation is allowed to run based on the current network connectivity. **See** [Network Mode](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode) for more information. |
+| `onError?` | (`error`: `TError`, `variables`: `TVariables`, `onMutateResult`: `TOnMutateResult` \| `undefined`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `unknown` | `undefined` | This function fires when the mutation encounters an error, and is passed the error. If a promise is returned, it is awaited before `onSettled` runs. |
+| `onMutate?` | (`variables`: `TVariables`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `TOnMutateResult` \| `Promise`\<`TOnMutateResult`\> | `undefined` | This function fires before the mutation function runs, and receives the same variables. Useful for optimistic updates applied in the hope that the mutation succeeds. The value it returns is passed to `onSuccess`, `onError` and `onSettled` as `onMutateResult`, which is where an optimistic update is usually rolled back. If a promise is returned, it is awaited before the mutation function runs. |
+| `onSettled?` | (`data`: `TData` \| `undefined`, `error`: `TError` \| `null`, `variables`: `TVariables`, `onMutateResult`: `TOnMutateResult` \| `undefined`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `unknown` | `undefined` | This function fires when the mutation either succeeds or errors, and is passed either the data or the error. If a promise is returned, it is awaited before the mutation settles. |
+| `onSuccess?` | (`data`: `TData`, `variables`: `TVariables`, `onMutateResult`: `TOnMutateResult`, `context`: [`MutationFunctionContext`](../type-aliases/MutationFunctionContext.md)) => `unknown` | `undefined` | This function fires when the mutation succeeds, and is passed the mutation's result. If a promise is returned, it is awaited before `onSettled` runs. |
+| `retry?` | \| `number` \| `false` \| `true` \| ((`failureCount`: `number`, `error`: `TError`) => `boolean`) | `0` | If `false`, failed mutations will not retry by default. If `true`, failed mutations will retry infinitely. If set to an integer number, e.g. 3, failed mutations will retry until the failed mutation count meets that number. If set to a function `(failureCount, error) => boolean` failed mutations will retry until the function returns false. |
+| `retryDelay?` | `number` \| ((`failureCount`: `number`, `error`: `TError`) => `number`) | `undefined` | This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. Defaults to a function that applies exponential backoff, capped at 30 seconds. |
+| `scope?` | [`MutationScope`](../type-aliases/MutationScope.md) | `undefined` | Controls whether this mutation runs alongside others or waits its turn. Mutations sharing the same `scope.id` run serially, in the order they were started. Without a scope, a mutation runs as soon as it is triggered. |
## Returns
[`CreateMutationResult`](../type-aliases/CreateMutationResult.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
-The mutation result. Value fields are exposed as a `Signal` — read `data`/`error` by calling them
-(e.g. `mutation.data()`) — while function fields (`mutate`, `mutateAsync`, `reset`) are called directly,
-unchanged. `isSuccess`/`isError`/`isPending`/`isIdle` are type-guard methods you can call to narrow whether
-`data` is defined.
-
-## Remarks
-
-`mutate`/`mutateAsync` also accept per-call `onSuccess`/`onError`/`onSettled` callbacks as a
-second argument, useful for triggering call-site side effects (e.g. navigation) without coupling them to
-the shared mutation definition. Callbacks defined in `injectMutationFn` fire for every mutation; per-call
-callbacks fire only for the latest call you've made — `mutateAsync` gives you a promise per call instead,
-so you can await `Promise.all`/`Promise.allSettled` over several calls and see each one's outcome.
+The mutation result, including `mutate` and `mutateAsync`.
## See
-[mutationOptions](mutationOptions.md) to share these options across multiple `injectMutation` call sites, or to look
-the mutation up elsewhere via its `mutationKey` (e.g. with `injectMutationState`).
+ - https://tanstack.com/query/latest/docs/framework/angular/guides/mutations
+ - [mutationOptions](mutationOptions.md) to share these options between `injectMutation` and `injectMutationState`.
-## Examples
+## Example
```angular-ts
@Component({
- selector: 'todos',
template: `
- @if (addMutation.isPending()) {
- Adding todo...
- } @else if (addMutation.isError()) {
-
An error occurred: {{ addMutation.error()?.message }}
+ @if (mutation.isPending()) {
+ Saving...
+ } @else if (mutation.isError()) {
+ Error: {{ mutation.error()?.message }}
}
-
+
`,
})
-export class Todos {
- readonly #queryClient = inject(QueryClient)
-
- readonly addMutation = injectMutation(() => ({
- mutationFn: addTodo,
- onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
- }))
-}
-```
-
-Optimistic update via `onMutate`, rolling back on `onError`:
-```angular-ts
-@Component({
- selector: 'todos',
- template: ``,
-})
-export class Todos {
- readonly #queryClient = inject(QueryClient)
-
- readonly addMutation = injectMutation(() => ({
- mutationFn: addTodo,
- onMutate: async (newTodo) => {
- await this.#queryClient.cancelQueries({ queryKey: ['todos'] })
- const previousTodos = this.#queryClient.getQueryData>(['todos'])
-
- this.#queryClient.setQueryData>(['todos'], (old) => [
- ...(old ?? []),
- newTodo,
- ])
-
- // Passed to `onError` as `onMutateResult` if the mutation fails.
- return { previousTodos }
- },
- onError: (_err, _newTodo, onMutateResult) => {
- this.#queryClient.setQueryData(['todos'], onMutateResult?.previousTodos)
- },
- onSettled: () => {
- this.#queryClient.invalidateQueries({ queryKey: ['todos'] })
- },
+export class CreatePost {
+ readonly mutation = injectMutation(() => ({
+ mutationFn: createPost,
}))
}
```
-
-Callbacks passed per call to `mutate` only fire for the last call — `mutateAsync` gives you a promise per
-call instead, so you can wait for all of them when they succeed:
-```angular-ts
-@Component({
- selector: 'todos',
- template: `
-
- `,
-})
-export class Todos {
- readonly #queryClient = inject(QueryClient)
-
- readonly addMutation = injectMutation(() => ({
- mutationFn: addTodo,
- onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
- }))
-
- async handleAddAll(todos: Array) {
- try {
- await Promise.all(todos.map((todo) => this.addMutation.mutateAsync(todo)))
- } catch (error) {
- console.error('Failed to add todos:', error)
- }
- }
-}
-```
-
-If some of the mutations above can fail independently of the others, and you want to know which ones did —
-rather than losing that information the moment the first one rejects — swap `Promise.all` for
-`Promise.allSettled`:
-```angular-ts
-@Component({
- selector: 'todos',
- template: `
-
- `,
-})
-export class Todos {
- readonly #queryClient = inject(QueryClient)
-
- readonly addMutation = injectMutation(() => ({
- mutationFn: addTodo,
- onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
- }))
-
- async handleAddAll(todos: Array) {
- const addResults = await Promise.allSettled(
- todos.map((todo) => this.addMutation.mutateAsync(todo)),
- )
-
- addResults.forEach((addResult, index) => {
- if (addResult.status === 'rejected') {
- console.error(`Failed to add "${todos[index]}":`, addResult.reason)
- }
- })
- }
-}
-```
diff --git a/docs/framework/angular/reference/functions/injectMutationState.md b/docs/framework/angular/reference/functions/injectMutationState.md
index 50a9a29da47..ac8fa2f5a73 100644
--- a/docs/framework/angular/reference/functions/injectMutationState.md
+++ b/docs/framework/angular/reference/functions/injectMutationState.md
@@ -6,13 +6,12 @@ title: injectMutationState
```ts
-function injectMutationState>(injectMutationStateFn?: () => MutationStateOptions, options?: InjectMutationStateOptions): Signal;
+function injectMutationState, TMutation extends Mutation = MutationTypeFromResult>(options?: () => MutationStateOptions): Signal;
```
-Defined in: [packages/angular-query-experimental/src/inject-mutation-state.ts:114](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation-state.ts#L114)
+Defined in: [packages/angular-query/src/inject-mutation-state.ts:70](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-mutation-state.ts#L70)
-Injects a signal that gives you access to all mutations in the `MutationCache`. You can pass `filters`
-([MutationFilters](../interfaces/MutationFilters.md)) to narrow down your mutations, and `select` to transform the mutation state.
+Injects a signal that tracks the state of all mutations.
## Type Parameters
@@ -20,21 +19,17 @@ Injects a signal that gives you access to all mutations in the `MutationCache`.
`TResult` = [`MutationState`](../interfaces/MutationState.md)\<`unknown`, `Error`, `unknown`, `unknown`\>
-## Parameters
-
-### injectMutationStateFn?
+### TMutation
-() => `MutationStateOptions`\<`TResult`\>
+`TMutation` *extends* [`Mutation`](../classes/Mutation.md)\<`any`, `any`, `any`, `any`\> = `MutationTypeFromResult`\<`TResult`\>
-A function returning the `filters` to narrow down matched mutations, and an
-optional `select` to transform the mutation state. Similar to `computed` from Angular, this function runs
-in the reactive context, so signals read inside it re-narrow the matched mutations.
+## Parameters
### options?
-[`InjectMutationStateOptions`](../interfaces/InjectMutationStateOptions.md)
+() => [`MutationStateOptions`](../type-aliases/MutationStateOptions.md)\<`TResult`, `TMutation`\>
-Additional configuration
+A function that returns mutation state options.
@@ -42,57 +37,11 @@ Additional configuration
| Property | Type | Description |
| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the mutation state signal. If this is not provided, the current injection context will be used instead (via `inject`). |
+| `filters?` | [`MutationFilters`](../interfaces/MutationFilters.md) | Restricts the mutation cache entries included in the result. |
+| `select?` | (`mutation`: `TMutation`) => `TResult` | Maps each matching mutation to the value exposed in the result signal. |
## Returns
`Signal`\<`TResult`[]\>
-A `Signal` with an Array of whatever `select` returns for each matching mutation.
-
-## Examples
-
-Get all variables of all running mutations:
-```angular-ts
-@Component({
- selector: 'pending-posts',
- template: `{{ pendingVariables().length }} posts saving...`,
-})
-export class PendingPosts {
- readonly pendingVariables = injectMutationState(() => ({
- filters: { status: 'pending' },
- select: (mutation) => mutation.state.variables,
- }))
-}
-```
-
-Get all data for specific mutations via the `mutationKey`:
-```angular-ts
-const mutationKey = ['posts']
-
-@Component({
- selector: 'posts',
- template: `
-
- `,
-})
-export class Posts {
- // Some mutation that we want to get the state for
- readonly createPostMutation = injectMutation(() => ({
- mutationKey,
- mutationFn: createPosts,
- }))
-
- readonly savedPosts = injectMutationState(() => ({
- // this mutation key needs to match the mutation key of the given mutation (see above)
- filters: { mutationKey, status: 'success' },
- select: (mutation) => mutation.state.data,
- }))
-
- createPost() {
- this.createPostMutation.mutate(['New Post'])
- }
-}
-```
+The signal that tracks the state of all mutations.
diff --git a/docs/framework/angular/reference/functions/injectQueries.md b/docs/framework/angular/reference/functions/injectQueries.md
new file mode 100644
index 00000000000..f44317cc1fd
--- /dev/null
+++ b/docs/framework/angular/reference/functions/injectQueries.md
@@ -0,0 +1,77 @@
+---
+id: injectQueries
+title: injectQueries
+---
+
+
+
+```ts
+function injectQueries["data"], CreateQueryResult["data"], InferDataAndError["error"]>, DefinedCreateQueryResult["data"], InferDataAndError["error"]>>] : T extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GenericGetDefinedOrUndefinedQueryResult["data"], CreateQueryResult["data"], InferDataAndError["error"]>, DefinedCreateQueryResult["data"], InferDataAndError["error"]>>, GenericGetDefinedOrUndefinedQueryResult["data"], CreateQueryResult["data"], InferDataAndError["error"]>, DefinedCreateQueryResult["data"], InferDataAndError["error"]>>] : [...Tails[]] extends [Head, ...Tails[]] ? [...Tails[]] extends [] ? [] : [...Tails[]] extends [Head] ? [GenericGetDefinedOrUndefinedQueryResult, DefinedCreateQueryResult<..., ...>>, GenericGetDefinedOrUndefinedQueryResult, DefinedCreateQueryResult<..., ...>>, GenericGetDefinedOrUndefinedQueryResult, DefinedCreateQueryResult<..., ...>>] : [...Tails[]] extends [Head, ...Tails[]] ? [...(...)[]] extends [] ? [] : ... extends ... ? ... : ... : [...{ [K in (...)]: (...) }[]] : [...{ [K in string | number | symbol]: GenericGetDefinedOrUndefinedQueryResult["data"], CreateQueryResult<(...)[(...)], (...)[(...)]>, DefinedCreateQueryResult<(...)[(...)], (...)[(...)]>> }[]] : { [K in string | number | symbol]: GenericGetDefinedOrUndefinedQueryResult["data"], CreateQueryResult["data"], InferDataAndError["error"]>, DefinedCreateQueryResult["data"], InferDataAndError["error"]>> }>(optionsFn: () => InjectQueriesOptions): Signal;
+```
+
+Defined in: [packages/angular-query/src/inject-queries.ts:55](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-queries.ts#L55)
+
+Injects multiple queries that run in parallel and react to Angular signals.
+
+## Type Parameters
+
+### T
+
+`T` *extends* `any`[]
+
+### TCombinedResult
+
+`TCombinedResult` = `T` *extends* \[\] ? \[\] : `T` *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>\] : `T` *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, ...\[...\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<..., ...\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<..., ...\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, ...\[...\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<..., ...\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<..., ...\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, ...\[...\], [`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<..., ...\>, [`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<..., ...\>\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...(...)[]`\] *extends* \[\] ? \[\] : ... *extends* ... ? ... : ... : \[`...{ [K in (...)]: (...) }[]`\] : \[...\{ \[K in string \| number \| symbol\]: GenericGetDefinedOrUndefinedQueryResult\\["data"\], CreateQueryResult\<(...)\[(...)\], (...)\[(...)\]\>, DefinedCreateQueryResult\<(...)\[(...)\], (...)\[(...)\]\>\> \}\[\]\] : \{ \[K in string \| number \| symbol\]: GenericGetDefinedOrUndefinedQueryResult\\["data"\], CreateQueryResult\\["data"\], InferDataAndError\\["error"\]\>, DefinedCreateQueryResult\\["data"\], InferDataAndError\\["error"\]\>\> \}
+
+## Parameters
+
+### optionsFn
+
+() => [`InjectQueriesOptions`](../interfaces/InjectQueriesOptions.md)\<`T`, `TCombinedResult`\>
+
+A function that returns the queries' options. Similar to `computed` from Angular,
+this function runs in the reactive context, so signals read inside it drive the queries.
+
+
+
+#### `optionsFn` properties
+
+| Property | Type | Description |
+| ------ | ------ | ------ |
+| `combine?` | (`result`: `T` *extends* \[\] ? \[\] : `T` *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], [`QueryObserverResult`](../type-aliases/QueryObserverResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, [`DefinedQueryObserverResult`](../type-aliases/DefinedQueryObserverResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>\] : `T` *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<...\>\[`"data"`\], [`QueryObserverResult`](../type-aliases/QueryObserverResult.md)\<...\[...\], ...\[...\]\>, [`DefinedQueryObserverResult`](../type-aliases/DefinedQueryObserverResult.md)\<...\[...\], ...\[...\]\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<...\>\[`"data"`\], [`QueryObserverResult`](../type-aliases/QueryObserverResult.md)\<...\[...\], ...\[...\]\>, [`DefinedQueryObserverResult`](../type-aliases/DefinedQueryObserverResult.md)\<...\[...\], ...\[...\]\>\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...(...)[]`\] *extends* \[...\] ? \[..., ..., ...\] : ... *extends* ... ? ... : ... : \[...\{ \[K in (...) \| (...) \| (...)\]: GenericGetDefinedOrUndefinedQueryResult\<(...), (...), (...), (...)\> \}\[\]\] : \{ \[K in string \| number \| symbol\]: GenericGetDefinedOrUndefinedQueryResult\\["data"\], QueryObserverResult\\["data"\], InferDataAndError\<(...)\[(...)\]\>\["error"\]\>, DefinedQueryObserverResult\\["data"\], InferDataAndError\<(...)\[(...)\]\>\["error"\]\>\> \}) => `TCombinedResult` | Projects the current plain observer results into a single reactively computed value. |
+| `queries` | \| readonly \[\{ \[K in string \| number \| symbol\]: GetCreateQueryOptionsForCreateQueries\ \}\] \| readonly \[`T` *extends* \[\] ? \[\] : `T` *extends* \[`Head`\] ? \[`GetCreateQueryOptionsForCreateQueries`\<`Head`\>\] : `T` *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GetCreateQueryOptionsForCreateQueries`\<`Head`\>, `GetCreateQueryOptionsForCreateQueries`\<`Head`\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...(...)[]`\] *extends* \[...\] ? \[..., ..., ...\] : ... *extends* ... ? ... : ... : readonly `unknown`[] *extends* \[`...Tails[]`\] ? \[`...Tails[]`\] : \[`...(...)[]`\] *extends* ...[] ? ...[] : ...[] : readonly `unknown`[] *extends* `T` ? `T` : `T` *extends* `QueryObserverOptionsForCreateQueries`\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>[] ? `QueryObserverOptionsForCreateQueries`\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>[] : `QueryObserverOptionsForCreateQueries`\<`unknown`, `Error`, `unknown`, readonly `unknown`[]\>[]\] | The ordered query options to observe; entries can be added, removed, or replaced reactively. |
+
+## Returns
+
+`Signal`\<`TCombinedResult`\>
+
+A signal containing the query results in the same order as the input queries.
+
+## See
+
+https://tanstack.com/query/latest/docs/framework/angular/guides/parallel-queries
+
+## Example
+
+```angular-ts
+@Component({
+ selector: 'users',
+ template: `
+ @for (query of userQueries(); track $index) {
+ @if (query.isSuccess()) {
+
{{ query.data().name }}
+ }
+ }
+ `,
+})
+export class UsersComponent {
+ readonly users = input.required>()
+
+ readonly userQueries = injectQueries(() => ({
+ queries: this.users().map((user) => ({
+ queryKey: ['user', user.id],
+ queryFn: () => fetchUserById(user.id),
+ })),
+ }))
+}
+```
diff --git a/docs/framework/angular/reference/functions/injectQuery.md b/docs/framework/angular/reference/functions/injectQuery.md
index e26af5742db..1998a908b4f 100644
--- a/docs/framework/angular/reference/functions/injectQuery.md
+++ b/docs/framework/angular/reference/functions/injectQuery.md
@@ -8,14 +8,14 @@ title: injectQuery
## Overview
```ts
-function injectQuery(injectQueryFn: () => DefinedInitialDataOptions, options?: InjectQueryOptions): DefinedCreateQueryResult;
-function injectQuery(injectQueryFn: () => UndefinedInitialDataOptions, options?: InjectQueryOptions): CreateQueryResult;
-function injectQuery(injectQueryFn: () => CreateQueryOptions, options?: InjectQueryOptions): CreateQueryResult;
+function injectQuery(optionsFn: () => DefinedInitialDataOptions): DefinedCreateQueryResult;
+function injectQuery(optionsFn: () => UndefinedInitialDataOptions): CreateQueryResult;
+function injectQuery(optionsFn: () => CreateQueryOptions): CreateQueryResult;
```
-- [`() => DefinedInitialDataOptions` → `DefinedCreateQueryResult`](#call-signature-1): This overload is selected when `initialData` is known to be defined on the options returned by `injectQueryFn`, so the resulting `data` signal is never `undefined` (unless a `select` changes `TData` to include `undefined`).
+- [`() => DefinedInitialDataOptions` → `DefinedCreateQueryResult`](#call-signature-1): This overload is selected when `initialData` is known to be defined on the options returned by `optionsFn`, so the resulting `data` signal is never `undefined` (unless a `select` changes `TData` to include `undefined`).
- [`() => UndefinedInitialDataOptions` → `CreateQueryResult`](#call-signature-2): Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
-- [`() => CreateQueryOptions` → `CreateQueryResult`](#call-signature-3): This overload accepts the general [CreateQueryOptions](../interfaces/CreateQueryOptions.md) shape rather than the `initialData`-aware overloads above, so whether `data` is defined can't be inferred from the call site — useful when wrapping `injectQuery` in your own helper function that forwards caller-provided options.
+- [`() => CreateQueryOptions` → `CreateQueryResult`](#call-signature-3): This overload accepts the general [CreateQueryOptions](../type-aliases/CreateQueryOptions.md) shape rather than the `initialData`-aware overloads above, so whether `data` is defined can't be inferred from the call site — useful when wrapping `injectQuery` in your own helper function that forwards caller-provided options.
See also: [Parameters](#parameters-summary) · [Returns](#returns-summary)
@@ -24,14 +24,13 @@ See also: [Parameters](#parameters-summary) · [Returns](#returns-summary)
## Call Signature
```ts
-function injectQuery(injectQueryFn: () => DefinedInitialDataOptions, options?: InjectQueryOptions): DefinedCreateQueryResult;
+function injectQuery(optionsFn: () => DefinedInitialDataOptions): DefinedCreateQueryResult;
```
-Defined in: [packages/angular-query-experimental/src/inject-query.ts:72](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L72)
+Defined in: [packages/angular-query/src/inject-query.ts:59](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-query.ts#L59)
-This overload is selected when `initialData` is known to be defined on the options returned by
-`injectQueryFn`, so the resulting `data` signal is never `undefined` (unless a `select` changes `TData` to
-include `undefined`).
+This overload is selected when `initialData` is known to be defined on the options returned by `optionsFn`, so the
+resulting `data` signal is never `undefined` (unless a `select` changes `TData` to include `undefined`).
### Type Parameters
@@ -53,20 +52,13 @@ include `undefined`).
### Parameters
-#### injectQueryFn
+#### optionsFn
() => [`DefinedInitialDataOptions`](../type-aliases/DefinedInitialDataOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
A function returning the [DefinedInitialDataOptions](../type-aliases/DefinedInitialDataOptions.md) to use — everything you
-can pass to `injectQuery`, with `initialData` known to be defined. Similar to `computed` from Angular, this
-function runs in the reactive context, so signals read inside it (in `queryKey`, `enabled`, etc.) drive the
-query.
-
-#### options?
-
-[`InjectQueryOptions`](../interfaces/InjectQueryOptions.md)
-
-Additional configuration
+can pass to `injectQuery`, with `initialData` known to be defined. Similar to `computed` from Angular, this function runs
+in the reactive context, so signals read inside it (in `queryKey`, `enabled`, etc.) drive the query.
### Returns
@@ -79,7 +71,7 @@ include `undefined`).
- https://tanstack.com/query/latest/docs/framework/angular/guides/queries
- [queryOptions](queryOptions.md) to share these options between `injectQuery` and imperative APIs like
-`queryClient.fetchQuery`.
+`queryClient.query`.
### Example
@@ -113,10 +105,10 @@ export class Posts {
## Call Signature
```ts
-function injectQuery(injectQueryFn: () => UndefinedInitialDataOptions, options?: InjectQueryOptions): CreateQueryResult;
+function injectQuery(optionsFn: () => UndefinedInitialDataOptions): CreateQueryResult;
```
-Defined in: [packages/angular-query-experimental/src/inject-query.ts:158](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L158)
+Defined in: [packages/angular-query/src/inject-query.ts:142](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-query.ts#L142)
Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
@@ -140,7 +132,7 @@ Injects a query: a declarative dependency on an asynchronous source of data that
### Parameters
-#### injectQueryFn
+#### optionsFn
() => [`UndefinedInitialDataOptions`](../type-aliases/UndefinedInitialDataOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
@@ -148,12 +140,6 @@ A function returning the [UndefinedInitialDataOptions](../type-aliases/Undefined
you can pass to `injectQuery`. Similar to `computed` from Angular, this function runs in the reactive
context, so signals read inside it (in `queryKey`, `enabled`, etc.) drive the query.
-#### options?
-
-[`InjectQueryOptions`](../interfaces/InjectQueryOptions.md)
-
-Additional configuration
-
### Returns
[`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`TData`, `TError`\>
@@ -166,7 +152,7 @@ the last fetch attempt failed, or `'success'` if the query has data to display.
- https://tanstack.com/query/latest/docs/framework/angular/guides/queries
- [queryOptions](queryOptions.md) to share these options between `injectQuery` and imperative APIs like
-`queryClient.fetchQuery`.
+`queryClient.query`.
### Examples
@@ -222,7 +208,6 @@ export class Posts {
readonly postsQuery = injectQuery(() => ({
queryKey: ['posts', this.filter()],
queryFn: () => fetchPosts(this.filter()),
- // Signals can be combined with expressions
enabled: !!this.filter(),
}))
}
@@ -233,12 +218,12 @@ export class Posts {
## Call Signature
```ts
-function injectQuery(injectQueryFn: () => CreateQueryOptions, options?: InjectQueryOptions): CreateQueryResult;
+function injectQuery(optionsFn: () => CreateQueryOptions): CreateQueryResult;
```
-Defined in: [packages/angular-query-experimental/src/inject-query.ts:184](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L184)
+Defined in: [packages/angular-query/src/inject-query.ts:165](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-query.ts#L165)
-This overload accepts the general [CreateQueryOptions](../interfaces/CreateQueryOptions.md) shape rather than the `initialData`-aware
+This overload accepts the general [CreateQueryOptions](../type-aliases/CreateQueryOptions.md) shape rather than the `initialData`-aware
overloads above, so whether `data` is defined can't be inferred from the call site — useful when wrapping
`injectQuery` in your own helper function that forwards caller-provided options.
@@ -262,19 +247,12 @@ overloads above, so whether `data` is defined can't be inferred from the call si
### Parameters
-#### injectQueryFn
+#### optionsFn
-() => [`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
+() => [`CreateQueryOptions`](../type-aliases/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
A function that returns query options. Similar to `computed` from Angular, this
-function runs in the reactive context, so signals read inside it (in `queryKey`, `enabled`, etc.) drive
-the query.
-
-#### options?
-
-[`InjectQueryOptions`](../interfaces/InjectQueryOptions.md)
-
-Additional configuration
+function runs in the reactive context, so signals read inside it drive the query.
### Returns
@@ -290,60 +268,18 @@ https://tanstack.com/query/latest/docs/framework/angular/guides/queries
## Parameters
-### injectQueryFn
+### optionsFn
-() => [`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
+() => [`CreateQueryOptions`](../type-aliases/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
A function that returns query options. Similar to `computed` from Angular, this
-function runs in the reactive context, so signals read inside it (in `queryKey`, `enabled`, etc.) drive
-the query.
-
-
-
-#### `injectQueryFn` properties
-
-| Property | Type | Default value | Description |
-| ------ | ------ | ------ | ------ |
-| `enabled?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean`) | `true` | Set this to `false` or a function that returns `false` to disable automatic refetching when the query mounts or changes query keys. To refetch the query, use the `refetch` method returned from the `useQuery` instance. Accepts a boolean or function that returns a boolean. |
-| `gcTime?` | `number` | `undefined` | The time in milliseconds that unused/inactive cache data remains in memory. When a query's cache becomes unused or inactive, that cache data will be garbage collected after this duration. When different garbage collection times are specified, the longest one will be used. Setting it to `Infinity` will disable garbage collection. Defaults to `5 * 60 * 1000` (5 minutes), or `Infinity` during SSR. Note: the maximum allowed time is about 24 days, imposed by `setTimeout`'s 32-bit signed integer delay — see `timeoutManager.setTimeoutProvider` for a workaround. |
-| `initialData?` | `TQueryFnData` \| (() => `TQueryFnData` \| `undefined`) | `undefined` | If set, this value will be used as the initial data for the query cache (as long as the query hasn't been created or cached yet). If set to a function, the function will be called **once** during the shared/root query initialization, and be expected to synchronously return the initial data. Initial data is considered stale by default unless a `staleTime` has been set. `initialData` **is persisted** to the cache. |
-| `initialDataUpdatedAt?` | `number` \| (() => `number` \| `undefined`) | `undefined` | If set, this value will be used as the time (in milliseconds) of when the `initialData` itself was last updated. |
-| `maxPages?` | `number` | `undefined` | Maximum number of pages to store in the data of an infinite query. |
-| `meta?` | `Record`\<`string`, `unknown`\> | `undefined` | Additional payload to be stored on each query. Use this property to pass information that can be used in other places. |
-| `networkMode?` | `"online"` \| `"always"` \| `"offlineFirst"` | `'online'` | Controls whether a query is allowed to run based on the current network connectivity. **See** [Network Mode](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode) for more information. |
-| `notifyOnChangeProps?` | \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `"all"` \| (() => \| `"all"` \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `undefined`) | `undefined` | If set, the component will only re-render if any of the listed properties change. When set to `['data', 'error']`, the component will only re-render when the `data` or `error` properties change. When set to `'all'`, the component will re-render whenever a query is updated. When set to a function, the function will be executed to compute the list of properties. Defaults to `undefined`, in which case property access is tracked automatically, and the component only re-renders when one of the tracked properties changes. |
-| `persister?` | (`queryFn`: (`context`: `object`) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>, `context`: `object`, `query`: [`Query`](../classes/Query.md)) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\> | `undefined` | This option can be used to persist the result of a query to an external storage, bypassing the need to actually call the `queryFn`. Useful for persisting a query's data across e.g. server/client boundaries. |
-| `placeholderData?` | \| `NonFunctionGuard`\<`TQueryFnData`\> \| ((`previousData`: `NonFunctionGuard`\<`TQueryFnData`\> \| `undefined`, `previousQuery`: \| [`Query`](../classes/Query.md)\<`NonFunctionGuard`\<`TQueryFnData`\>, `TError`, `NonFunctionGuard`\<`TQueryFnData`\>, `TQueryKey`\> \| `undefined`) => `NonFunctionGuard`\<`TQueryFnData`\> \| `undefined`) | `undefined` | If set, this value will be used as the placeholder data for this particular query observer while the query is still in the `loading` data and no initialData has been provided. |
-| `queryFn?` | \| *typeof* [`skipToken`](../variables/skipToken.md) \| ((`context`: `object`) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>) | `undefined` | The function that the query will use to request data. Required, unless a default query function has been set via `queryClient.setQueryDefaults` or `queryClient.setDefaultOptions`. Receives a [QueryFunctionContext](../type-aliases/QueryFunctionContext.md). Must return a promise that will either resolve data or throw an error. The data cannot be `undefined`. |
-| `queryHash?` | `string` | `undefined` | The hashed form of `queryKey`, computed with `queryKeyHashFn` (or the default hashing function otherwise). Used as the actual cache key internally. |
-| `queryKey` | `TQueryKey` & `object` | `undefined` | The query key to use for this query. The query key will be hashed into a stable hash. See [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for more information. The query will automatically update when this key changes (as long as `enabled` is not set to `false`). |
-| `queryKeyHashFn?` | (`queryKey`: `TQueryKey`) => `string` | `undefined` | If specified, this function is used to hash the `queryKey` to a string. |
-| `refetchInterval?` | \| `number` \| `false` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `number` \| `false` \| `undefined`) | `false` | If set to a number, the query will continuously refetch at this frequency in milliseconds. If set to a function, the function will be executed with the latest data and query to compute a frequency |
-| `refetchIntervalInBackground?` | `boolean` | `false` | If set to `true`, the query will continue to refetch while their tab/window is in the background. |
-| `refetchOnMount?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on mount if the data is stale. If set to `false`, will disable additional instances of a query to trigger background refetch. If set to `'always'`, the query will always refetch on mount (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value |
-| `refetchOnReconnect?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `undefined` | If set to `true`, the query will refetch on reconnect if the data is stale. If set to `false`, the query will not refetch on reconnect. If set to `'always'`, the query will always refetch on reconnect (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. Defaults to `true` unless `networkMode` is `'always'`. |
-| `refetchOnWindowFocus?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on window focus if the data is stale. If set to `false`, the query will not refetch on window focus. If set to `'always'`, the query will always refetch on window focus (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. |
-| `retry?` | \| `number` \| `false` \| `true` \| ((`failureCount`: `number`, `error`: `TError`) => `boolean`) | `undefined` | If `false`, failed queries will not retry by default. If `true`, failed queries will retry infinitely. If set to an integer number, e.g. 3, failed queries will retry until the failed query count meets that number. If set to a function `(failureCount, error) => boolean` failed queries will retry until the function returns false. Defaults to `3` on the client and `0` on the server. |
-| `retryDelay?` | `number` \| ((`failureCount`: `number`, `error`: `TError`) => `number`) | `undefined` | This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff. A function like `attempt => attempt * 1000` applies linear backoff. Defaults to a function that applies exponential backoff, capped at 30 seconds. |
-| `retryOnMount?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean`) | `true` | If set to `false`, the query will not be retried on mount if it contains an error. If set to a function, the function will be executed with the query to compute the value. |
-| `select?` | (`data`: `TQueryFnData`) => `TData` | `undefined` | This option can be used to transform or select a part of the data returned by the query function. It affects the returned `data` value, but does not affect what gets stored in the query cache. The `select` function will only run if `data` changed, or if the reference to the `select` function itself changes. To optimize, memoize the function so its reference stays stable across calls. |
-| `staleTime?` | \| `number` \| `"static"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `number` \| `"static"`) | `0` | The time in milliseconds after data is considered stale. If set to `Infinity`, the data will never be considered stale. If set to `'static'`, the data will never be considered stale. If set to a function, the function will be executed with the query to compute a `staleTime`. |
-| `structuralSharing?` | `boolean` \| ((`oldData`: `unknown`, `newData`: `unknown`) => `unknown`) | `true` | Set this to `false` to disable structural sharing between query results. Set this to a function which accepts the old and new data and returns resolved data of the same type to implement custom structural sharing logic. |
-| `throwOnError?` | \| `false` \| `true` \| ((`error`: `TError`, `query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean`) | `false` | Whether errors should be thrown instead of setting the `error` property. If set to `true` or `suspense` is `true`, all errors will be thrown to the error boundary. If set to `false` and `suspense` is `false`, errors are returned as state. If set to a function, it will be passed the error and the query, and it should return a boolean indicating whether to show the error in an error boundary (`true`) or return the error as state (`false`). |
-
-### options?
-
-[`InjectQueryOptions`](../interfaces/InjectQueryOptions.md)
-
-Additional configuration
-
-
-
-#### `options` properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the query. If this is not provided, the current injection context will be used instead (via `inject`). |
+function runs in the reactive context, so signals read inside it drive the query.
+
+
+
+#### `optionsFn` properties
+
+Built from [`QueryObserverOptions`](../interfaces/QueryObserverOptions.md#properties). See the type above for what it changes.
diff --git a/docs/framework/angular/reference/functions/injectQueryClient.md b/docs/framework/angular/reference/functions/injectQueryClient.md
deleted file mode 100644
index 92e5c6bf136..00000000000
--- a/docs/framework/angular/reference/functions/injectQueryClient.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-id: injectQueryClient
-title: injectQueryClient
----
-
-
-
-```ts
-function injectQueryClient(injectOptions?: InjectOptions & object): QueryClient;
-```
-
-Defined in: [packages/angular-query-experimental/src/inject-query-client.ts:18](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query-client.ts#L18)
-
-Injects a `QueryClient` instance and allows passing a custom injector.
-
-## Parameters
-
-### injectOptions?
-
-`InjectOptions` & `object` = `{}`
-
-Type of the options argument to inject and optionally a custom injector.
-
-## Returns
-
-[`QueryClient`](../classes/QueryClient.md)
-
-The `QueryClient` instance.
-
-## Deprecated
-
-Use `inject(QueryClient)` instead.
-If you need to get a `QueryClient` from a custom injector, use `injector.get(QueryClient)`.
-
-**Example**
-```ts
-const queryClient = injectQueryClient();
-```
diff --git a/docs/framework/angular/reference/functions/mutationOptions.md b/docs/framework/angular/reference/functions/mutationOptions.md
index c59d1481dc2..137c4560551 100644
--- a/docs/framework/angular/reference/functions/mutationOptions.md
+++ b/docs/framework/angular/reference/functions/mutationOptions.md
@@ -25,7 +25,7 @@ See also: [Parameters](#parameters-summary) · [Returns](#returns-summary)
function mutationOptions(options: WithRequired, "mutationKey">): WithRequired, "mutationKey">;
```
-Defined in: [packages/angular-query-experimental/src/mutation-options.ts:38](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/mutation-options.ts#L38)
+Defined in: [packages/angular-query/src/mutation-options.ts:38](https://github.com/TanStack/query/blob/main/packages/angular-query/src/mutation-options.ts#L38)
You can generally pass everything to `mutationOptions` that you can also pass to `injectMutation`. A
`mutationKey` is required on this overload so the mutation can be looked up later, e.g. with
@@ -72,7 +72,7 @@ The same options object, unchanged.
Looking the mutation up elsewhere via its `mutationKey`, e.g. for a global "saving…" indicator:
```angular-ts
-import { mutationOptions, injectMutationState } from '@tanstack/angular-query-experimental'
+import { mutationOptions, injectMutationState } from '@tanstack/angular-query'
const createPostOptions = mutationOptions({
mutationKey: ['posts', 'create'],
@@ -103,7 +103,7 @@ export class SavingIndicator {
function mutationOptions(options: Omit, "mutationKey">): Omit, "mutationKey">;
```
-Defined in: [packages/angular-query-experimental/src/mutation-options.ts:94](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/mutation-options.ts#L94)
+Defined in: [packages/angular-query/src/mutation-options.ts:94](https://github.com/TanStack/query/blob/main/packages/angular-query/src/mutation-options.ts#L94)
You can generally pass everything to `mutationOptions` that you can also pass to `injectMutation`. No
`mutationKey` is required on this overload — use this when you don't need to target the mutation via a
@@ -155,7 +155,7 @@ See the other overload's example for looking a mutation up via `injectMutationSt
Sharing options across services, so `QueriesService` stays the single place a mutation is defined:
```angular-ts
-import { mutationOptions, injectMutation } from '@tanstack/angular-query-experimental'
+import { mutationOptions, injectMutation } from '@tanstack/angular-query'
@Injectable({ providedIn: 'root' })
export class QueriesService {
diff --git a/docs/framework/angular/reference/functions/provideAngularQuery.md b/docs/framework/angular/reference/functions/provideAngularQuery.md
deleted file mode 100644
index ae60f31c7b4..00000000000
--- a/docs/framework/angular/reference/functions/provideAngularQuery.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-id: provideAngularQuery
-title: provideAngularQuery
----
-
-
-
-```ts
-function provideAngularQuery(queryClient: QueryClient): Provider[];
-```
-
-Defined in: [packages/angular-query-experimental/src/providers.ts:115](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L115)
-
-Sets up providers necessary to enable TanStack Query functionality for Angular applications.
-
-Allows configuring a `QueryClient`.
-
-## Parameters
-
-### queryClient
-
-[`QueryClient`](../classes/QueryClient.md)
-
-A `QueryClient` instance.
-
-## Returns
-
-`Provider`[]
-
-A set of providers to set up TanStack Query.
-
-## See
-
-https://tanstack.com/query/v5/docs/framework/angular/quick-start
-
-## Deprecated
-
-Use `provideTanStackQuery` instead.
diff --git a/docs/framework/angular/reference/functions/provideIsRestoring.md b/docs/framework/angular/reference/functions/provideIsRestoring.md
deleted file mode 100644
index 2f50bfc2180..00000000000
--- a/docs/framework/angular/reference/functions/provideIsRestoring.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-id: provideIsRestoring
-title: provideIsRestoring
----
-
-
-
-```ts
-function provideIsRestoring(isRestoring: Signal): Provider;
-```
-
-Defined in: [packages/angular-query-experimental/src/inject-is-restoring.ts:48](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-restoring.ts#L48)
-
-Registers a provider for the restore state read by `injectIsRestoring`. Wire this up wherever you drive a
-restore yourself — e.g. a persist-client integration — so `injectQuery` and friends can defer subscribing
-to their observer (avoiding a race with the restore) until the restore signal flips back to `false`.
-
-## Parameters
-
-### isRestoring
-
-`Signal`\<`boolean`\>
-
-A readonly `Signal` that tracks the restore state.
-
-## Returns
-
-`Provider`
-
-A provider for the `isRestoring` signal.
diff --git a/docs/framework/angular/reference/functions/provideQueryClient.md b/docs/framework/angular/reference/functions/provideQueryClient.md
deleted file mode 100644
index 3267fda20e3..00000000000
--- a/docs/framework/angular/reference/functions/provideQueryClient.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-id: provideQueryClient
-title: provideQueryClient
----
-
-
-
-```ts
-function provideQueryClient(queryClient:
- | QueryClient
- | InjectionToken): Provider;
-```
-
-Defined in: [packages/angular-query-experimental/src/providers.ts:21](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L21)
-
-Usually [provideTanStackQuery](provideTanStackQuery.md) is used once to set up TanStack Query and the
-[`QueryClient`](https://tanstack.com/query/latest/docs/reference/QueryClient) for the entire application —
-it calls `provideQueryClient` internally. Use `provideQueryClient` directly to provide a different
-`QueryClient` instance for part of the application, or for unit testing.
-
-## Parameters
-
-### queryClient
-
- \| [`QueryClient`](../classes/QueryClient.md)
- \| `InjectionToken`\<[`QueryClient`](../classes/QueryClient.md)\>
-
-A `QueryClient` instance, or an `InjectionToken` which provides a `QueryClient`.
-
-## Returns
-
-`Provider`
-
-A provider object that can be used to provide the `QueryClient` instance.
-
-## Example
-
-Providing a test-only `QueryClient` in a component test, without wiring up `provideTanStackQuery`'s other
-defaults:
-```ts
-TestBed.configureTestingModule({
- providers: [provideQueryClient(new QueryClient())],
-})
-```
diff --git a/docs/framework/angular/reference/functions/provideTanStackQuery.md b/docs/framework/angular/reference/functions/provideTanStackQuery.md
index 9fe89fd95f5..cba33a1b29a 100644
--- a/docs/framework/angular/reference/functions/provideTanStackQuery.md
+++ b/docs/framework/angular/reference/functions/provideTanStackQuery.md
@@ -6,88 +6,64 @@ title: provideTanStackQuery
```ts
-function provideTanStackQuery(queryClient:
- | QueryClient
- | InjectionToken, ...features: QueryFeatures[]): Provider[];
+function provideTanStackQuery(queryClientFactory: () => QueryClient, ...features: readonly QueryFeature[]): EnvironmentProviders;
```
-Defined in: [packages/angular-query-experimental/src/providers.ts:96](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L96)
+Defined in: [packages/angular-query/src/providers.ts:101](https://github.com/TanStack/query/blob/main/packages/angular-query/src/providers.ts#L101)
-Sets up providers necessary to enable TanStack Query functionality for Angular applications. Allows
-configuring a `QueryClient` and optional features such as developer tools.
+Provides a `QueryClient` and optional TanStack Query features.
+The factory runs once per injector in Angular's injection context, so it can
+call `inject()` and each SSR request can receive an independent cache.
## Parameters
-### queryClient
+### queryClientFactory
- \| [`QueryClient`](../classes/QueryClient.md)
- \| `InjectionToken`\<[`QueryClient`](../classes/QueryClient.md)\>
+() => [`QueryClient`](../classes/QueryClient.md)
-A `QueryClient` instance, or an `InjectionToken` which provides a `QueryClient`.
+Creates or resolves a `QueryClient` in the injection context.
### features
-...[`QueryFeatures`](../type-aliases/QueryFeatures.md)[]
+...readonly [`QueryFeature`](../interfaces/QueryFeature.md)[]
Optional features to configure additional Query functionality.
## Returns
-`Provider`[]
+`EnvironmentProviders`
-A set of providers to set up TanStack Query.
+A single EnvironmentProviders value (do not spread into `providers`).
## See
- https://tanstack.com/query/v5/docs/framework/angular/quick-start
- - withDevtools
+ - https://tanstack.com/query/v5/docs/framework/angular/devtools
+ - https://tanstack.com/query/latest/docs/framework/angular/guides/ssr
-## Examples
+## Example
-```ts
-import { provideTanStackQuery, QueryClient } from '@tanstack/angular-query-experimental'
-
-bootstrapApplication(AppComponent, {
- providers: [provideTanStackQuery(new QueryClient())],
-})
-```
-
-The same, in an `NgModule`-based application:
-```ts
-import { provideTanStackQuery, QueryClient } from '@tanstack/angular-query-experimental'
-
-@NgModule({
- declarations: [AppComponent],
- imports: [BrowserModule],
- providers: [provideTanStackQuery(new QueryClient())],
- bootstrap: [AppComponent],
-})
-export class AppModule {}
-```
-
-Enabling optional developer tools by adding `withDevtools` — by default, the tools are then loaded when
-your app is in development mode:
```ts
import {
provideTanStackQuery,
- withDevtools,
QueryClient,
-} from '@tanstack/angular-query-experimental'
+} from '@tanstack/angular-query'
bootstrapApplication(AppComponent, {
- providers: [provideTanStackQuery(new QueryClient(), withDevtools())],
+ providers: [provideTanStackQuery(() => new QueryClient())],
})
```
-Using an `InjectionToken` for the `QueryClient` — an advanced optimization that lets TanStack Query be
-absent from the main application bundle, useful for including it on lazy-loaded routes only while still
-sharing a `QueryClient`. This is a small optimization; for most applications it's preferable to provide
-the `QueryClient` in the main application config, as in the examples above:
+You can also enable optional developer tools by adding `withDevtools`. By
+default the tools will then be loaded when your app is in development mode.
+
```ts
-export const MY_QUERY_CLIENT = new InjectionToken('', {
- factory: () => new QueryClient(),
-})
+import { provideTanStackQuery, QueryClient } from '@tanstack/angular-query'
+import { withDevtools } from '@tanstack/angular-query-devtools'
-// In a lazy loaded route or lazy loaded component's providers array:
-providers: [provideTanStackQuery(MY_QUERY_CLIENT)]
+bootstrapApplication(AppComponent, {
+ providers: [
+ provideTanStackQuery(() => new QueryClient(), withDevtools()),
+ ],
+})
```
diff --git a/docs/framework/angular/reference/functions/queryFeature.md b/docs/framework/angular/reference/functions/queryFeature.md
deleted file mode 100644
index a34eec7c09b..00000000000
--- a/docs/framework/angular/reference/functions/queryFeature.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-id: queryFeature
-title: queryFeature
----
-
-
-
-```ts
-function queryFeature(kind: TFeatureKind, providers: Provider[]): QueryFeature;
-```
-
-Defined in: [packages/angular-query-experimental/src/providers.ts:143](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L143)
-
-Helper function to create an object that represents a Query feature.
-
-## Type Parameters
-
-### TFeatureKind
-
-`TFeatureKind` *extends* `"Devtools"` \| `"PersistQueryClient"`
-
-## Parameters
-
-### kind
-
-`TFeatureKind`
-
-The kind of feature, e.g. `'Devtools'`.
-
-### providers
-
-`Provider`[]
-
-The Angular providers this feature contributes to `provideTanStackQuery`.
-
-## Returns
-
-[`QueryFeature`](../interfaces/QueryFeature.md)\<`TFeatureKind`\>
-
-A Query feature.
-
-
-
-### Result properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `ɵkind` | `TFeatureKind` | The kind of the feature, e.g. `'Devtools'` or `'PersistQueryClient'`. |
-| `ɵproviders` | `Provider`[] | The providers that `provideTanStackQuery` registers for the feature. |
diff --git a/docs/framework/angular/reference/functions/queryOptions.md b/docs/framework/angular/reference/functions/queryOptions.md
index 5eb7abaa74f..4cc9926c654 100644
--- a/docs/framework/angular/reference/functions/queryOptions.md
+++ b/docs/framework/angular/reference/functions/queryOptions.md
@@ -13,9 +13,9 @@ function queryOptions(options: UndefinedInitialDataOptions): UndefinedInitialDataOptions & QueryKeyWithDataTag;
```
-- [`DefinedInitialDataOptions` → `DefinedInitialDataOptions & QueryKeyWithDataTag`](#call-signature-1): You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options can be shared across functions and imperative APIs such as `queryClient.fetchQuery`. `options.queryKey` is required and is the query key to generate options for.
-- [`UnusedSkipTokenOptions` → `UnusedSkipTokenOptions & QueryKeyWithDataTag`](#call-signature-2): You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options can be shared across functions and imperative APIs such as `queryClient.fetchQuery`. `options.queryKey` is required and is the query key to generate options for.
-- [`UndefinedInitialDataOptions` → `UndefinedInitialDataOptions & QueryKeyWithDataTag`](#call-signature-3): You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options can be shared across functions and imperative APIs such as `queryClient.fetchQuery`. `options.queryKey` is required and is the query key to generate options for.
+- [`DefinedInitialDataOptions` → `DefinedInitialDataOptions & QueryKeyWithDataTag`](#call-signature-1): You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options can be shared across functions and imperative APIs such as `queryClient.query`. `options.queryKey` is required and is the query key to generate options for.
+- [`UnusedSkipTokenOptions` → `UnusedSkipTokenOptions & QueryKeyWithDataTag`](#call-signature-2): You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options can be shared across functions and imperative APIs such as `queryClient.query`. `options.queryKey` is required and is the query key to generate options for.
+- [`UndefinedInitialDataOptions` → `UndefinedInitialDataOptions & QueryKeyWithDataTag`](#call-signature-3): You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options can be shared across functions and imperative APIs such as `queryClient.query`. `options.queryKey` is required and is the query key to generate options for.
See also: [Parameters](#parameters-summary) · [Returns](#returns-summary)
@@ -27,10 +27,10 @@ See also: [Parameters](#parameters-summary) · [Returns](#returns-summary)
function queryOptions(options: DefinedInitialDataOptions): DefinedInitialDataOptions & QueryKeyWithDataTag;
```
-Defined in: [packages/angular-query-experimental/src/query-options.ts:149](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L149)
+Defined in: [packages/angular-query/src/query-options.ts:132](https://github.com/TanStack/query/blob/main/packages/angular-query/src/query-options.ts#L132)
You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options
-can be shared across functions and imperative APIs such as `queryClient.fetchQuery`. `options.queryKey` is
+can be shared across functions and imperative APIs such as `queryClient.query`. `options.queryKey` is
required and is the query key to generate options for.
This overload is selected when `initialData` is known to be defined, so the resulting `data` is never
@@ -77,7 +77,7 @@ The same options object, typed so that `queryKey` carries the inferred data type
### Example
```angular-ts
-import { queryOptions, injectQuery } from '@tanstack/angular-query-experimental'
+import { queryOptions, injectQuery } from '@tanstack/angular-query'
export const postsOptions = queryOptions({
queryKey: ['posts'],
@@ -113,10 +113,10 @@ export class Posts {
function queryOptions(options: UnusedSkipTokenOptions): UnusedSkipTokenOptions & QueryKeyWithDataTag;
```
-Defined in: [packages/angular-query-experimental/src/query-options.ts:196](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L196)
+Defined in: [packages/angular-query/src/query-options.ts:179](https://github.com/TanStack/query/blob/main/packages/angular-query/src/query-options.ts#L179)
You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options
-can be shared across functions and imperative APIs such as `queryClient.fetchQuery`. `options.queryKey` is
+can be shared across functions and imperative APIs such as `queryClient.query`. `options.queryKey` is
required and is the query key to generate options for.
### Type Parameters
@@ -160,7 +160,7 @@ The same options object, typed so that `queryKey` carries the inferred data type
A parameterized factory, so the same options object can be reused per `id`:
```angular-ts
-import { queryOptions, injectQuery } from '@tanstack/angular-query-experimental'
+import { queryOptions, injectQuery } from '@tanstack/angular-query'
export const postOptions = (id: string) =>
queryOptions({
@@ -194,10 +194,10 @@ export class Post {
function queryOptions(options: UndefinedInitialDataOptions): UndefinedInitialDataOptions & QueryKeyWithDataTag;
```
-Defined in: [packages/angular-query-experimental/src/query-options.ts:274](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L274)
+Defined in: [packages/angular-query/src/query-options.ts:257](https://github.com/TanStack/query/blob/main/packages/angular-query/src/query-options.ts#L257)
You can generally pass everything to `queryOptions` that you can also pass to `injectQuery`. These options
-can be shared across functions and imperative APIs such as `queryClient.fetchQuery`. `options.queryKey` is
+can be shared across functions and imperative APIs such as `queryClient.query`. `options.queryKey` is
required and is the query key to generate options for.
### Type Parameters
@@ -245,7 +245,7 @@ This is the only overload that accepts `queryFn: skipToken`, shown below.
A parameterized factory, so the same options object can be reused per `id`:
```angular-ts
-import { queryOptions, injectQuery } from '@tanstack/angular-query-experimental'
+import { queryOptions, injectQuery } from '@tanstack/angular-query'
export const postOptions = (id: string) =>
queryOptions({
@@ -273,7 +273,7 @@ export class Post {
A factory that disables the query, type safe, until `postId` is set:
```angular-ts
-import { queryOptions, skipToken, injectQuery } from '@tanstack/angular-query-experimental'
+import { queryOptions, skipToken, injectQuery } from '@tanstack/angular-query'
export const postOptions = (postId: number | undefined) =>
queryOptions({
@@ -315,7 +315,7 @@ The [UndefinedInitialDataOptions](../type-aliases/UndefinedInitialDataOptions.md
#### `options` properties
-Built from [`CreateQueryOptions`](../interfaces/CreateQueryOptions.md#properties). See the type above for what it changes.
+Built from [`QueryObserverOptions`](../interfaces/QueryObserverOptions.md#properties). See the type above for what it changes.
@@ -329,4 +329,4 @@ The same options object, typed so that `queryKey` carries the inferred data type
### Result properties
-Built from [`CreateQueryOptions`](../interfaces/CreateQueryOptions.md#properties), [`QueryKeyWithDataTag`](../type-aliases/QueryKeyWithDataTag.md#properties). See the type above for what it changes.
+Built from [`QueryObserverOptions`](../interfaces/QueryObserverOptions.md#properties), [`QueryKeyWithDataTag`](../type-aliases/QueryKeyWithDataTag.md#properties). See the type above for what it changes.
diff --git a/docs/framework/angular/reference/functions/toResource.md b/docs/framework/angular/reference/functions/toResource.md
new file mode 100644
index 00000000000..20cd4c44c58
--- /dev/null
+++ b/docs/framework/angular/reference/functions/toResource.md
@@ -0,0 +1,48 @@
+---
+id: toResource
+title: toResource
+---
+
+
+
+```ts
+function toResource(query: QueryResourceSource): QueryResource;
+```
+
+Defined in: [packages/angular-query/src/query-resource.ts:44](https://github.com/TanStack/query/blob/main/packages/angular-query/src/query-resource.ts#L44)
+
+Converts an Angular Query result into Angular's Resource interface.
+
+Warning: experimental feature. The API may change in minor and patch releases.
+Pin your package version to an exact version when using this feature.
+
+Call this function once and reuse the returned resource.
+
+## Type Parameters
+
+### TValue
+
+`TValue`
+
+## Parameters
+
+### query
+
+`QueryResourceSource`\<`TValue`\>
+
+An Angular Query or infinite-query result.
+
+## Returns
+
+[`QueryResource`](../interfaces/QueryResource.md)\<`TValue`\>
+
+A Resource-compatible view of the query result.
+
+
+
+### Result properties
+
+| Property | Modifier | Type | Description | Overrides |
+| ------ | ------ | ------ | ------ | ------ |
+| `reload` | `public` | () => `boolean` | Requests a new query fetch only when the current query data is stale. Used for compatibility with Angular APIs that might want to reload a resource, like Signal Forms' validateAsync resource interface. | - |
+| `snapshot` | `readonly` | `Signal`\<`ResourceSnapshot`\<`TValue`\>\> | The current query state as a single snapshot. | `Resource.snapshot` |
diff --git a/docs/framework/angular/reference/functions/withHydrationKey.md b/docs/framework/angular/reference/functions/withHydrationKey.md
new file mode 100644
index 00000000000..e93e4236d5c
--- /dev/null
+++ b/docs/framework/angular/reference/functions/withHydrationKey.md
@@ -0,0 +1,39 @@
+---
+id: withHydrationKey
+title: withHydrationKey
+---
+
+
+
+```ts
+function withHydrationKey(key: string): QueryFeature;
+```
+
+Defined in: [packages/angular-query/src/providers.ts:173](https://github.com/TanStack/query/blob/main/packages/angular-query/src/providers.ts#L173)
+
+Sets a non-default serialization key for this injector's `QueryClient` cache (server dehydrate /
+browser hydrate via `TransferState`). Use this when you have multiple `QueryClient` instances
+so each has its own key. The default key applies when you do not add this feature.
+
+```ts
+providers: [
+ provideTanStackQuery(
+ () => new QueryClient(),
+ withHydrationKey('my-secondary-query-cache'),
+ ),
+]
+```
+
+## Parameters
+
+### key
+
+`string`
+
+A unique string for this client's `TransferState` entry.
+
+## Returns
+
+[`QueryFeature`](../interfaces/QueryFeature.md)
+
+A feature that stores this client's cache under the supplied key.
diff --git a/docs/framework/angular/reference/functions/withNoQueryHydration.md b/docs/framework/angular/reference/functions/withNoQueryHydration.md
new file mode 100644
index 00000000000..19db03d0ba1
--- /dev/null
+++ b/docs/framework/angular/reference/functions/withNoQueryHydration.md
@@ -0,0 +1,20 @@
+---
+id: withNoQueryHydration
+title: withNoQueryHydration
+---
+
+
+
+```ts
+function withNoQueryHydration(): QueryFeature;
+```
+
+Defined in: [packages/angular-query/src/providers.ts:188](https://github.com/TanStack/query/blob/main/packages/angular-query/src/providers.ts#L188)
+
+Disables `TransferState` hydration and dehydration for the current environment injector.
+
+## Returns
+
+[`QueryFeature`](../interfaces/QueryFeature.md)
+
+A feature that prevents automatic cache transfer for this injector.
diff --git a/docs/framework/angular/reference/index.md b/docs/framework/angular/reference/index.md
index c1414521479..4625e0f7a52 100644
--- a/docs/framework/angular/reference/index.md
+++ b/docs/framework/angular/reference/index.md
@@ -1,6 +1,6 @@
---
-id: "@tanstack/angular-query-experimental"
-title: "@tanstack/angular-query-experimental"
+id: "@tanstack/angular-query"
+title: "@tanstack/angular-query"
---
@@ -20,14 +20,15 @@ title: "@tanstack/angular-query-experimental"
## Interfaces
+- [BaseInfiniteQueryNarrowing](interfaces/BaseInfiniteQueryNarrowing.md)
- [BaseMutationNarrowing](interfaces/BaseMutationNarrowing.md)
- [BaseQueryNarrowing](interfaces/BaseQueryNarrowing.md)
- [CancelOptions](interfaces/CancelOptions.md)
-- [CreateBaseQueryOptions](interfaces/CreateBaseQueryOptions.md)
- [CreateInfiniteQueryOptions](interfaces/CreateInfiniteQueryOptions.md)
- [CreateMutationOptions](interfaces/CreateMutationOptions.md)
-- [CreateQueryOptions](interfaces/CreateQueryOptions.md)
- [DefaultOptions](interfaces/DefaultOptions.md)
+- [DefinedInfiniteQueryNarrowing](interfaces/DefinedInfiniteQueryNarrowing.md)
+- [DefinedQueryNarrowing](interfaces/DefinedQueryNarrowing.md)
- [DehydratedState](interfaces/DehydratedState.md)
- [DehydrateOptions](interfaces/DehydrateOptions.md)
- [~~EnsureQueryDataOptions~~](interfaces/EnsureQueryDataOptions.md)
@@ -47,12 +48,7 @@ title: "@tanstack/angular-query-experimental"
- [InfiniteQueryObserverSuccessResult](interfaces/InfiniteQueryObserverSuccessResult.md)
- [InfiniteQueryPageParamsOptions](interfaces/InfiniteQueryPageParamsOptions.md)
- [InitialPageParam](interfaces/InitialPageParam.md)
-- [InjectInfiniteQueryOptions](interfaces/InjectInfiniteQueryOptions.md)
-- [InjectIsFetchingOptions](interfaces/InjectIsFetchingOptions.md)
-- [InjectIsMutatingOptions](interfaces/InjectIsMutatingOptions.md)
-- [InjectMutationOptions](interfaces/InjectMutationOptions.md)
-- [InjectMutationStateOptions](interfaces/InjectMutationStateOptions.md)
-- [InjectQueryOptions](interfaces/InjectQueryOptions.md)
+- [InjectQueriesOptions](interfaces/InjectQueriesOptions.md)
- [InvalidateOptions](interfaces/InvalidateOptions.md)
- [InvalidateQueryFilters](interfaces/InvalidateQueryFilters.md)
- [MutateOptions](interfaces/MutateOptions.md)
@@ -83,6 +79,7 @@ title: "@tanstack/angular-query-experimental"
- [QueryObserverRefetchErrorResult](interfaces/QueryObserverRefetchErrorResult.md)
- [QueryObserverSuccessResult](interfaces/QueryObserverSuccessResult.md)
- [QueryOptions](interfaces/QueryOptions.md)
+- [QueryResource](interfaces/QueryResource.md)
- [QueryState](interfaces/QueryState.md)
- [RefetchOptions](interfaces/RefetchOptions.md)
- [RefetchQueryFilters](interfaces/RefetchQueryFilters.md)
@@ -101,6 +98,7 @@ title: "@tanstack/angular-query-experimental"
- [CreateMutateAsyncFunction](type-aliases/CreateMutateAsyncFunction.md)
- [CreateMutateFunction](type-aliases/CreateMutateFunction.md)
- [CreateMutationResult](type-aliases/CreateMutationResult.md)
+- [CreateQueryOptions](type-aliases/CreateQueryOptions.md)
- [CreateQueryResult](type-aliases/CreateQueryResult.md)
- [DataTag](type-aliases/DataTag.md)
- [dataTagErrorSymbol](type-aliases/dataTagErrorSymbol.md)
@@ -114,7 +112,6 @@ title: "@tanstack/angular-query-experimental"
- [DefinedInitialDataInfiniteOptions](type-aliases/DefinedInitialDataInfiniteOptions.md)
- [DefinedInitialDataOptions](type-aliases/DefinedInitialDataOptions.md)
- [DefinedQueryObserverResult](type-aliases/DefinedQueryObserverResult.md)
-- [DevtoolsFeature](type-aliases/DevtoolsFeature.md)
- [DistributiveOmit](type-aliases/DistributiveOmit.md)
- [~~EnsureInfiniteQueryDataOptions~~](type-aliases/EnsureInfiniteQueryDataOptions.md)
- [~~FetchInfiniteQueryOptions~~](type-aliases/FetchInfiniteQueryOptions.md)
@@ -136,6 +133,7 @@ title: "@tanstack/angular-query-experimental"
- [MutationMeta](type-aliases/MutationMeta.md)
- [MutationObserverResult](type-aliases/MutationObserverResult.md)
- [MutationScope](type-aliases/MutationScope.md)
+- [MutationStateOptions](type-aliases/MutationStateOptions.md)
- [MutationStatus](type-aliases/MutationStatus.md)
- [NetworkMode](type-aliases/NetworkMode.md)
- [NonUndefinedGuard](type-aliases/NonUndefinedGuard.md)
@@ -143,14 +141,12 @@ title: "@tanstack/angular-query-experimental"
- [NotifyOnChangeProps](type-aliases/NotifyOnChangeProps.md)
- [OmitKeyof](type-aliases/OmitKeyof.md)
- [Override](type-aliases/Override.md)
-- [PersistQueryClientFeature](type-aliases/PersistQueryClientFeature.md)
- [PlaceholderDataFunction](type-aliases/PlaceholderDataFunction.md)
- [QueriesOptions](type-aliases/QueriesOptions.md)
- [QueriesPlaceholderDataFunction](type-aliases/QueriesPlaceholderDataFunction.md)
- [QueriesResults](type-aliases/QueriesResults.md)
- [QueryBooleanOption](type-aliases/QueryBooleanOption.md)
- [QueryCacheNotifyEvent](type-aliases/QueryCacheNotifyEvent.md)
-- [QueryFeatures](type-aliases/QueryFeatures.md)
- [QueryFunction](type-aliases/QueryFunction.md)
- [QueryFunctionContext](type-aliases/QueryFunctionContext.md)
- [QueryKey](type-aliases/QueryKey.md)
@@ -204,8 +200,8 @@ title: "@tanstack/angular-query-experimental"
- [injectIsRestoring](functions/injectIsRestoring.md)
- [injectMutation](functions/injectMutation.md)
- [injectMutationState](functions/injectMutationState.md)
+- [injectQueries](functions/injectQueries.md)
- [injectQuery](functions/injectQuery.md)
-- [~~injectQueryClient~~](functions/injectQueryClient.md)
- [~~isCancelledError~~](functions/isCancelledError.md)
- [keepPreviousData](functions/keepPreviousData.md)
- [matchMutation](functions/matchMutation.md)
@@ -213,11 +209,10 @@ title: "@tanstack/angular-query-experimental"
- [mutationOptions](functions/mutationOptions.md)
- [noop](functions/noop.md)
- [partialMatchKey](functions/partialMatchKey.md)
-- [~~provideAngularQuery~~](functions/provideAngularQuery.md)
-- [provideIsRestoring](functions/provideIsRestoring.md)
-- [provideQueryClient](functions/provideQueryClient.md)
- [provideTanStackQuery](functions/provideTanStackQuery.md)
-- [queryFeature](functions/queryFeature.md)
- [queryOptions](functions/queryOptions.md)
- [replaceEqualDeep](functions/replaceEqualDeep.md)
- [shouldThrowError](functions/shouldThrowError.md)
+- [toResource](functions/toResource.md)
+- [withHydrationKey](functions/withHydrationKey.md)
+- [withNoQueryHydration](functions/withNoQueryHydration.md)
diff --git a/docs/framework/angular/reference/interfaces/BaseInfiniteQueryNarrowing.md b/docs/framework/angular/reference/interfaces/BaseInfiniteQueryNarrowing.md
new file mode 100644
index 00000000000..99e74d7dd94
--- /dev/null
+++ b/docs/framework/angular/reference/interfaces/BaseInfiniteQueryNarrowing.md
@@ -0,0 +1,28 @@
+---
+id: BaseInfiniteQueryNarrowing
+title: BaseInfiniteQueryNarrowing
+---
+
+
+
+Defined in: [packages/angular-query/src/types.ts:138](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L138)
+
+Signal-backed guards that narrow a paginated query result by its current status.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = [`DefaultError`](../type-aliases/DefaultError.md)
+
+## Properties
+
+| Property | Type | Description |
+| ------ | ------ | ------ |
+| `isError` | `SignalFunction`\<(`this`: [`CreateInfiniteQueryResult`](../type-aliases/CreateInfiniteQueryResult.md)\<`TData`, `TError`\>) => `this is CreateInfiniteQueryResult>`\> | Returns whether the result failed and narrows its data and error signals. |
+| `isPending` | `SignalFunction`\<(`this`: [`CreateInfiniteQueryResult`](../type-aliases/CreateInfiniteQueryResult.md)\<`TData`, `TError`\>) => `this is CreateInfiniteQueryResult>`\> | Narrows the result to the pending state when that state is possible. |
+| `isSuccess` | `SignalFunction`\<(`this`: [`CreateInfiniteQueryResult`](../type-aliases/CreateInfiniteQueryResult.md)\<`TData`, `TError`\>) => `this is CreateInfiniteQueryResult>`\> | Returns whether the result is successful and narrows its data and error signals. |
diff --git a/docs/framework/angular/reference/interfaces/BaseMutationNarrowing.md b/docs/framework/angular/reference/interfaces/BaseMutationNarrowing.md
index be469b2106d..81d6573be7e 100644
--- a/docs/framework/angular/reference/interfaces/BaseMutationNarrowing.md
+++ b/docs/framework/angular/reference/interfaces/BaseMutationNarrowing.md
@@ -5,11 +5,9 @@ title: BaseMutationNarrowing
-Defined in: [packages/angular-query-experimental/src/types.ts:324](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L324)
+Defined in: [packages/angular-query/src/types.ts:423](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L423)
-The `isSuccess`/`isError`/`isPending`/`isIdle` methods on a mutation result. Each is both a `Signal`
-(its current boolean value is read reactively without calling it) and a type-guard function you can
-call — `if (mutation.isSuccess())` — so that `mutation.data` narrows away `undefined` inside the branch.
+Signal-backed guards that narrow mutation data, errors, and variables by the current status.
## Type Parameters
@@ -17,27 +15,18 @@ call — `if (mutation.isSuccess())` — so that `mutation.data` narrows away `u
`TData` = `unknown`
-The type your mutation function resolves to.
-
### TError
`TError` = [`DefaultError`](../type-aliases/DefaultError.md)
-The type of errors your mutation function may throw.
-
### TVariables
`TVariables` = `unknown`
-The type of the variable passed to `mutate`/`mutateAsync`.
-
### TOnMutateResult
`TOnMutateResult` = `unknown`
-The type returned by `onMutate`, passed to `onSuccess`/`onError`/`onSettled` as
-their `onMutateResult` parameter — useful for optimistic-update rollback data.
-
## Properties
| Property | Type | Description |
diff --git a/docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md b/docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md
index b0043d4e127..b7d8bda7471 100644
--- a/docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md
+++ b/docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md
@@ -5,12 +5,9 @@ title: BaseQueryNarrowing
-Defined in: [packages/angular-query-experimental/src/types.ts:80](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L80)
+Defined in: [packages/angular-query/src/types.ts:72](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L72)
-The `isSuccess`/`isError`/`isPending` methods on a query result. Unlike `react-query`'s derived booleans,
-these are type-guard methods you call — `if (query.isSuccess())` — so that `query.data` narrows away
-`undefined` inside the branch, the same way `status` narrowing works on the plain object `react-query`
-returns.
+Signal-backed guards that narrow a query result and its data and error fields by status.
## Type Parameters
@@ -18,18 +15,14 @@ returns.
`TData` = `unknown`
-The type `data` ends up as after `select` runs.
-
### TError
`TError` = [`DefaultError`](../type-aliases/DefaultError.md)
-The type of errors your `queryFn` may throw.
-
## Properties
| Property | Type | Description |
| ------ | ------ | ------ |
-| `isError` | (`this`: [`CreateBaseQueryResult`](../type-aliases/CreateBaseQueryResult.md)\<`TData`, `TError`\>) => `this is CreateBaseQueryResult>` | Returns `true` if the query is in the `error` state, narrowing the result to that state. |
-| `isPending` | (`this`: [`CreateBaseQueryResult`](../type-aliases/CreateBaseQueryResult.md)\<`TData`, `TError`\>) => `this is CreateBaseQueryResult>` | Returns `true` if the query is in the `pending` state, narrowing the result to that state. |
-| `isSuccess` | (`this`: [`CreateBaseQueryResult`](../type-aliases/CreateBaseQueryResult.md)\<`TData`, `TError`\>) => `this is CreateBaseQueryResult>` | Returns `true` if the query is in the `success` state, narrowing the result to that state. |
+| `isError` | `SignalFunction`\<() => `this is CreateBaseQueryResult>`\> | Returns whether the result failed and narrows its data and error signals. |
+| `isPending` | `SignalFunction`\<() => `this is CreateBaseQueryResult>`\> | Narrows the result to the pending state when that state is possible. |
+| `isSuccess` | `SignalFunction`\<() => `this is CreateBaseQueryResult>`\> | Returns whether the result is successful and narrows its data and error signals. |
diff --git a/docs/framework/angular/reference/interfaces/CreateBaseQueryOptions.md b/docs/framework/angular/reference/interfaces/CreateBaseQueryOptions.md
deleted file mode 100644
index 2f4c9f4fa8b..00000000000
--- a/docs/framework/angular/reference/interfaces/CreateBaseQueryOptions.md
+++ /dev/null
@@ -1,82 +0,0 @@
----
-id: CreateBaseQueryOptions
-title: CreateBaseQueryOptions
----
-
-
-
-Defined in: [packages/angular-query-experimental/src/types.ts:33](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L33)
-
-The options shared across `angular-query-experimental`'s query functions. Extends
-[QueryObserverOptions](QueryObserverOptions.md) from `@tanstack/query-core` as-is — unlike `react-query`,
-`angular-query-experimental` has no extra framework-specific option here.
-
-## Extends
-
-- [`QueryObserverOptions`](QueryObserverOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryData`, `TQueryKey`\>
-
-## Type Parameters
-
-### TQueryFnData
-
-`TQueryFnData` = `unknown`
-
-The type your `queryFn` resolves to.
-
-### TError
-
-`TError` = [`DefaultError`](../type-aliases/DefaultError.md)
-
-The type of errors your `queryFn` may throw.
-
-### TData
-
-`TData` = `TQueryFnData`
-
-The type `data` ends up as after `select` runs. Defaults to `TQueryFnData` when no
-`select` is used.
-
-### TQueryData
-
-`TQueryData` = `TQueryFnData`
-
-The type of the data actually held in the query cache — the input to `select` and
-`placeholderData`. Defaults to, and is usually the same as, `TQueryFnData`.
-
-### TQueryKey
-
-`TQueryKey` *extends* [`QueryKey`](../type-aliases/QueryKey.md) = [`QueryKey`](../type-aliases/QueryKey.md)
-
-The type of your `queryKey`.
-
-## Properties
-
-| Property | Type | Default value | Description |
-| ------ | ------ | ------ | ------ |
-| `enabled?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryData`, `TQueryKey`\>) => `boolean`) | `true` | Set this to `false` or a function that returns `false` to disable automatic refetching when the query mounts or changes query keys. To refetch the query, use the `refetch` method returned from the `useQuery` instance. Accepts a boolean or function that returns a boolean. |
-| `gcTime?` | `number` | `undefined` | The time in milliseconds that unused/inactive cache data remains in memory. When a query's cache becomes unused or inactive, that cache data will be garbage collected after this duration. When different garbage collection times are specified, the longest one will be used. Setting it to `Infinity` will disable garbage collection. Defaults to `5 * 60 * 1000` (5 minutes), or `Infinity` during SSR. Note: the maximum allowed time is about 24 days, imposed by `setTimeout`'s 32-bit signed integer delay — see `timeoutManager.setTimeoutProvider` for a workaround. |
-| `initialData?` | `TQueryData` \| (() => `TQueryData` \| `undefined`) | `undefined` | If set, this value will be used as the initial data for the query cache (as long as the query hasn't been created or cached yet). If set to a function, the function will be called **once** during the shared/root query initialization, and be expected to synchronously return the initial data. Initial data is considered stale by default unless a `staleTime` has been set. `initialData` **is persisted** to the cache. |
-| `initialDataUpdatedAt?` | `number` \| (() => `number` \| `undefined`) | `undefined` | If set, this value will be used as the time (in milliseconds) of when the `initialData` itself was last updated. |
-| `maxPages?` | `number` | `undefined` | Maximum number of pages to store in the data of an infinite query. |
-| `meta?` | `Record`\<`string`, `unknown`\> | `undefined` | Additional payload to be stored on each query. Use this property to pass information that can be used in other places. |
-| `networkMode?` | `"online"` \| `"always"` \| `"offlineFirst"` | `'online'` | Controls whether a query is allowed to run based on the current network connectivity. **See** [Network Mode](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode) for more information. |
-| `notifyOnChangeProps?` | \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `"all"` \| (() => \| `"all"` \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `undefined`) | `undefined` | If set, the component will only re-render if any of the listed properties change. When set to `['data', 'error']`, the component will only re-render when the `data` or `error` properties change. When set to `'all'`, the component will re-render whenever a query is updated. When set to a function, the function will be executed to compute the list of properties. Defaults to `undefined`, in which case property access is tracked automatically, and the component only re-renders when one of the tracked properties changes. |
-| `persister?` | (`queryFn`: (`context`: `object`) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>, `context`: `object`, `query`: [`Query`](../classes/Query.md)) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\> | `undefined` | This option can be used to persist the result of a query to an external storage, bypassing the need to actually call the `queryFn`. Useful for persisting a query's data across e.g. server/client boundaries. |
-| `placeholderData?` | \| `NonFunctionGuard`\<`TQueryData`\> \| ((`previousData`: `NonFunctionGuard`\<`TQueryData`\> \| `undefined`, `previousQuery`: \| [`Query`](../classes/Query.md)\<`NonFunctionGuard`\<`TQueryData`\>, `TError`, `NonFunctionGuard`\<`TQueryData`\>, `TQueryKey`\> \| `undefined`) => `NonFunctionGuard`\<`TQueryData`\> \| `undefined`) | `undefined` | If set, this value will be used as the placeholder data for this particular query observer while the query is still in the `loading` data and no initialData has been provided. |
-| `queryFn?` | \| *typeof* [`skipToken`](../variables/skipToken.md) \| ((`context`: `object`) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>) | `undefined` | The function that the query will use to request data. Required, unless a default query function has been set via `queryClient.setQueryDefaults` or `queryClient.setDefaultOptions`. Receives a [QueryFunctionContext](../type-aliases/QueryFunctionContext.md). Must return a promise that will either resolve data or throw an error. The data cannot be `undefined`. |
-| `queryHash?` | `string` | `undefined` | The hashed form of `queryKey`, computed with `queryKeyHashFn` (or the default hashing function otherwise). Used as the actual cache key internally. |
-| `queryKey` | `TQueryKey` & `object` | `undefined` | The query key to use for this query. The query key will be hashed into a stable hash. See [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for more information. The query will automatically update when this key changes (as long as `enabled` is not set to `false`). |
-| `queryKeyHashFn?` | (`queryKey`: `TQueryKey`) => `string` | `undefined` | If specified, this function is used to hash the `queryKey` to a string. |
-| `refetchInterval?` | \| `number` \| `false` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryData`, `TQueryKey`\>) => `number` \| `false` \| `undefined`) | `false` | If set to a number, the query will continuously refetch at this frequency in milliseconds. If set to a function, the function will be executed with the latest data and query to compute a frequency |
-| `refetchIntervalInBackground?` | `boolean` | `false` | If set to `true`, the query will continue to refetch while their tab/window is in the background. |
-| `refetchOnMount?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on mount if the data is stale. If set to `false`, will disable additional instances of a query to trigger background refetch. If set to `'always'`, the query will always refetch on mount (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value |
-| `refetchOnReconnect?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `undefined` | If set to `true`, the query will refetch on reconnect if the data is stale. If set to `false`, the query will not refetch on reconnect. If set to `'always'`, the query will always refetch on reconnect (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. Defaults to `true` unless `networkMode` is `'always'`. |
-| `refetchOnWindowFocus?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on window focus if the data is stale. If set to `false`, the query will not refetch on window focus. If set to `'always'`, the query will always refetch on window focus (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. |
-| `retry?` | \| `number` \| `false` \| `true` \| ((`failureCount`: `number`, `error`: `TError`) => `boolean`) | `undefined` | If `false`, failed queries will not retry by default. If `true`, failed queries will retry infinitely. If set to an integer number, e.g. 3, failed queries will retry until the failed query count meets that number. If set to a function `(failureCount, error) => boolean` failed queries will retry until the function returns false. Defaults to `3` on the client and `0` on the server. |
-| `retryDelay?` | `number` \| ((`failureCount`: `number`, `error`: `TError`) => `number`) | `undefined` | This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff. A function like `attempt => attempt * 1000` applies linear backoff. Defaults to a function that applies exponential backoff, capped at 30 seconds. |
-| `retryOnMount?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryData`, `TQueryKey`\>) => `boolean`) | `true` | If set to `false`, the query will not be retried on mount if it contains an error. If set to a function, the function will be executed with the query to compute the value. |
-| `select?` | (`data`: `TQueryData`) => `TData` | `undefined` | This option can be used to transform or select a part of the data returned by the query function. It affects the returned `data` value, but does not affect what gets stored in the query cache. The `select` function will only run if `data` changed, or if the reference to the `select` function itself changes. To optimize, memoize the function so its reference stays stable across calls. |
-| `staleTime?` | \| `number` \| `"static"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryData`, `TQueryKey`\>) => `number` \| `"static"`) | `0` | The time in milliseconds after data is considered stale. If set to `Infinity`, the data will never be considered stale. If set to `'static'`, the data will never be considered stale. If set to a function, the function will be executed with the query to compute a `staleTime`. |
-| `structuralSharing?` | `boolean` \| ((`oldData`: `unknown`, `newData`: `unknown`) => `unknown`) | `true` | Set this to `false` to disable structural sharing between query results. Set this to a function which accepts the old and new data and returns resolved data of the same type to implement custom structural sharing logic. |
-| `suspense?` | `boolean` | `false` | If set to `true`, the query will suspend when `status === 'pending'` and throw errors when `status === 'error'`. |
-| `throwOnError?` | \| `false` \| `true` \| ((`error`: `TError`, `query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryData`, `TQueryKey`\>) => `boolean`) | `false` | Whether errors should be thrown instead of setting the `error` property. If set to `true` or `suspense` is `true`, all errors will be thrown to the error boundary. If set to `false` and `suspense` is `false`, errors are returned as state. If set to a function, it will be passed the error and the query, and it should return a boolean indicating whether to show the error in an error boundary (`true`) or return the error as state (`false`). |
diff --git a/docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md b/docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md
index ade6e903b34..3b903bae81d 100644
--- a/docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md
+++ b/docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md
@@ -5,16 +5,13 @@ title: CreateInfiniteQueryOptions
-Defined in: [packages/angular-query-experimental/src/types.ts:126](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L126)
+Defined in: [packages/angular-query/src/types.ts:222](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L222)
-The options accepted by `injectInfiniteQuery`. Same as [CreateBaseQueryOptions](CreateBaseQueryOptions.md), minus `suspense` —
-which `angular-query-experimental` doesn't support, unlike `react-query` — extends
-[InfiniteQueryObserverOptions](InfiniteQueryObserverOptions.md) from `@tanstack/query-core` for the infinite-query-specific options
-(`getNextPageParam`, `initialPageParam`, etc.).
+Options accepted by `injectInfiniteQuery`, including page parameters and pagination callbacks.
## Extends
-- [`OmitKeyof`](../type-aliases/OmitKeyof.md)\<[`InfiniteQueryObserverOptions`](InfiniteQueryObserverOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>, `"suspense"`\>
+- [`OmitKeyof`](../type-aliases/OmitKeyof.md)\<[`InfiniteQueryObserverOptions`](InfiniteQueryObserverOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>, `"notifyOnChangeProps"` \| `"suspense"` \| `"throwOnError"`\>
## Type Parameters
@@ -22,34 +19,22 @@ which `angular-query-experimental` doesn't support, unlike `react-query` — ext
`TQueryFnData` = `unknown`
-The type of a single page, as your `queryFn` resolves it.
-
### TError
`TError` = [`DefaultError`](../type-aliases/DefaultError.md)
-The type of errors your `queryFn` may throw.
-
### TData
`TData` = `TQueryFnData`
-The type `data` ends up as after `select` runs. Defaults to `TQueryFnData` here, though
-`injectInfiniteQuery` itself defaults it to `InfiniteData` — the shape `data` actually has
-when no `select` is used.
-
### TQueryKey
`TQueryKey` *extends* [`QueryKey`](../type-aliases/QueryKey.md) = [`QueryKey`](../type-aliases/QueryKey.md)
-The type of your `queryKey`.
-
### TPageParam
`TPageParam` = `unknown`
-The type of the parameter passed to `queryFn` to fetch a given page.
-
## Properties
| Property | Type | Default value | Description |
@@ -64,7 +49,6 @@ The type of the parameter passed to `queryFn` to fetch a given page.
| `maxPages?` | `number` | `undefined` | Maximum number of pages to store in the data of an infinite query. |
| `meta?` | `Record`\<`string`, `unknown`\> | `undefined` | Additional payload to be stored on each query. Use this property to pass information that can be used in other places. |
| `networkMode?` | `"online"` \| `"always"` \| `"offlineFirst"` | `'online'` | Controls whether a query is allowed to run based on the current network connectivity. **See** [Network Mode](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode) for more information. |
-| `notifyOnChangeProps?` | \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `"all"` \| (() => \| `"all"` \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `undefined`) | `undefined` | If set, the component will only re-render if any of the listed properties change. When set to `['data', 'error']`, the component will only re-render when the `data` or `error` properties change. When set to `'all'`, the component will re-render whenever a query is updated. When set to a function, the function will be executed to compute the list of properties. Defaults to `undefined`, in which case property access is tracked automatically, and the component only re-renders when one of the tracked properties changes. |
| `persister?` | (`queryFn`: (`context`: [`QueryFunctionContext`](../type-aliases/QueryFunctionContext.md)\<`NoInfer`\<`TQueryKey`\>, `TPageParam`\>) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>, `context`: `object`, `query`: [`Query`](../classes/Query.md)) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\> | `undefined` | This option can be used to persist the result of a query to an external storage, bypassing the need to actually call the `queryFn`. Useful for persisting a query's data across e.g. server/client boundaries. |
| `placeholderData?` | \| [`InfiniteData`](InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| ((`previousData`: \| [`InfiniteData`](InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| `undefined`, `previousQuery`: \| [`Query`](../classes/Query.md)\<[`InfiniteData`](InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TError`, [`InfiniteData`](InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\> \| `undefined`) => \| [`InfiniteData`](InfiniteData.md)\<`TQueryFnData`, `TPageParam`\> \| `undefined`) | `undefined` | If set, this value will be used as the placeholder data for this particular query observer while the query is still in the `loading` data and no initialData has been provided. |
| `queryFn?` | \| *typeof* [`skipToken`](../variables/skipToken.md) \| ((`context`: [`QueryFunctionContext`](../type-aliases/QueryFunctionContext.md)\<`TQueryKey`, `TPageParam`\>) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>) | `undefined` | The function that the query will use to request data. Required, unless a default query function has been set via `queryClient.setQueryDefaults` or `queryClient.setDefaultOptions`. Receives a [QueryFunctionContext](../type-aliases/QueryFunctionContext.md). Must return a promise that will either resolve data or throw an error. The data cannot be `undefined`. |
@@ -82,4 +66,3 @@ The type of the parameter passed to `queryFn` to fetch a given page.
| `select?` | (`data`: [`InfiniteData`](InfiniteData.md)) => `TData` | `undefined` | This option can be used to transform or select a part of the data returned by the query function. It affects the returned `data` value, but does not affect what gets stored in the query cache. The `select` function will only run if `data` changed, or if the reference to the `select` function itself changes. To optimize, memoize the function so its reference stays stable across calls. |
| `staleTime?` | \| `number` \| `"static"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `number` \| `"static"`) | `0` | The time in milliseconds after data is considered stale. If set to `Infinity`, the data will never be considered stale. If set to `'static'`, the data will never be considered stale. If set to a function, the function will be executed with the query to compute a `staleTime`. |
| `structuralSharing?` | `boolean` \| ((`oldData`: `unknown`, `newData`: `unknown`) => `unknown`) | `true` | Set this to `false` to disable structural sharing between query results. Set this to a function which accepts the old and new data and returns resolved data of the same type to implement custom structural sharing logic. |
-| `throwOnError?` | \| `false` \| `true` \| ((`error`: `TError`, `query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, [`InfiniteData`](InfiniteData.md)\<`TQueryFnData`, `TPageParam`\>, `TQueryKey`\>) => `boolean`) | `false` | Whether errors should be thrown instead of setting the `error` property. If set to `true` or `suspense` is `true`, all errors will be thrown to the error boundary. If set to `false` and `suspense` is `false`, errors are returned as state. If set to a function, it will be passed the error and the query, and it should return a boolean indicating whether to show the error in an error boundary (`true`) or return the error as state (`false`). |
diff --git a/docs/framework/angular/reference/interfaces/CreateMutationOptions.md b/docs/framework/angular/reference/interfaces/CreateMutationOptions.md
index 2cf74b7d6d7..6a436c17ceb 100644
--- a/docs/framework/angular/reference/interfaces/CreateMutationOptions.md
+++ b/docs/framework/angular/reference/interfaces/CreateMutationOptions.md
@@ -5,14 +5,14 @@ title: CreateMutationOptions
-Defined in: [packages/angular-query-experimental/src/types.ts:223](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L223)
+Defined in: [packages/angular-query/src/types.ts:332](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L332)
The options accepted by `injectMutation`. Same as [MutationObserverOptions](MutationObserverOptions.md) from
`@tanstack/query-core`, minus the internal `_defaulted` flag.
## Extends
-- [`OmitKeyof`](../type-aliases/OmitKeyof.md)\<[`MutationObserverOptions`](MutationObserverOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>, `"_defaulted"`\>
+- [`OmitKeyof`](../type-aliases/OmitKeyof.md)\<[`MutationObserverOptions`](MutationObserverOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>, `"_defaulted"` \| `"throwOnError"`\>
## Type Parameters
@@ -57,4 +57,3 @@ their `onMutateResult` parameter — useful for optimistic-update rollback data.
| `retry?` | \| `number` \| `false` \| `true` \| ((`failureCount`: `number`, `error`: `TError`) => `boolean`) | `0` | If `false`, failed mutations will not retry by default. If `true`, failed mutations will retry infinitely. If set to an integer number, e.g. 3, failed mutations will retry until the failed mutation count meets that number. If set to a function `(failureCount, error) => boolean` failed mutations will retry until the function returns false. |
| `retryDelay?` | `number` \| ((`failureCount`: `number`, `error`: `TError`) => `number`) | `undefined` | This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. Defaults to a function that applies exponential backoff, capped at 30 seconds. |
| `scope?` | [`MutationScope`](../type-aliases/MutationScope.md) | `undefined` | Controls whether this mutation runs alongside others or waits its turn. Mutations sharing the same `scope.id` run serially, in the order they were started. Without a scope, a mutation runs as soon as it is triggered. |
-| `throwOnError?` | `boolean` \| ((`error`: `TError`) => `boolean`) | `false` | Whether errors should be thrown instead of setting the `error` property. If set to `true`, all errors will be thrown to the nearest error boundary. If set to a function, it will be passed the error and should return a boolean indicating whether to throw the error (`true`) or return it as state (`false`). |
diff --git a/docs/framework/angular/reference/interfaces/CreateQueryOptions.md b/docs/framework/angular/reference/interfaces/CreateQueryOptions.md
deleted file mode 100644
index 13dd257ec9c..00000000000
--- a/docs/framework/angular/reference/interfaces/CreateQueryOptions.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-id: CreateQueryOptions
-title: CreateQueryOptions
----
-
-
-
-Defined in: [packages/angular-query-experimental/src/types.ts:56](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L56)
-
-The options accepted by `injectQuery`. Same as [CreateBaseQueryOptions](CreateBaseQueryOptions.md), minus `suspense` — which
-`angular-query-experimental` doesn't support, unlike `react-query`.
-
-## Extends
-
-- [`OmitKeyof`](../type-aliases/OmitKeyof.md)\<[`CreateBaseQueryOptions`](CreateBaseQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryFnData`, `TQueryKey`\>, `"suspense"`\>
-
-## Type Parameters
-
-### TQueryFnData
-
-`TQueryFnData` = `unknown`
-
-The type your `queryFn` resolves to.
-
-### TError
-
-`TError` = [`DefaultError`](../type-aliases/DefaultError.md)
-
-The type of errors your `queryFn` may throw.
-
-### TData
-
-`TData` = `TQueryFnData`
-
-The type `data` ends up as after `select` runs. Defaults to `TQueryFnData` when no
-`select` is used.
-
-### TQueryKey
-
-`TQueryKey` *extends* [`QueryKey`](../type-aliases/QueryKey.md) = [`QueryKey`](../type-aliases/QueryKey.md)
-
-The type of your `queryKey`.
-
-## Properties
-
-| Property | Type | Default value | Description |
-| ------ | ------ | ------ | ------ |
-| `enabled?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean`) | `true` | Set this to `false` or a function that returns `false` to disable automatic refetching when the query mounts or changes query keys. To refetch the query, use the `refetch` method returned from the `useQuery` instance. Accepts a boolean or function that returns a boolean. |
-| `gcTime?` | `number` | `undefined` | The time in milliseconds that unused/inactive cache data remains in memory. When a query's cache becomes unused or inactive, that cache data will be garbage collected after this duration. When different garbage collection times are specified, the longest one will be used. Setting it to `Infinity` will disable garbage collection. Defaults to `5 * 60 * 1000` (5 minutes), or `Infinity` during SSR. Note: the maximum allowed time is about 24 days, imposed by `setTimeout`'s 32-bit signed integer delay — see `timeoutManager.setTimeoutProvider` for a workaround. |
-| `initialData?` | `TQueryFnData` \| (() => `TQueryFnData` \| `undefined`) | `undefined` | If set, this value will be used as the initial data for the query cache (as long as the query hasn't been created or cached yet). If set to a function, the function will be called **once** during the shared/root query initialization, and be expected to synchronously return the initial data. Initial data is considered stale by default unless a `staleTime` has been set. `initialData` **is persisted** to the cache. |
-| `initialDataUpdatedAt?` | `number` \| (() => `number` \| `undefined`) | `undefined` | If set, this value will be used as the time (in milliseconds) of when the `initialData` itself was last updated. |
-| `maxPages?` | `number` | `undefined` | Maximum number of pages to store in the data of an infinite query. |
-| `meta?` | `Record`\<`string`, `unknown`\> | `undefined` | Additional payload to be stored on each query. Use this property to pass information that can be used in other places. |
-| `networkMode?` | `"online"` \| `"always"` \| `"offlineFirst"` | `'online'` | Controls whether a query is allowed to run based on the current network connectivity. **See** [Network Mode](https://tanstack.com/query/latest/docs/framework/react/guides/network-mode) for more information. |
-| `notifyOnChangeProps?` | \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `"all"` \| (() => \| `"all"` \| ( \| `"error"` \| `"data"` \| `"isError"` \| `"isPending"` \| `"isLoading"` \| `"isLoadingError"` \| `"isRefetchError"` \| `"isSuccess"` \| `"isPlaceholderData"` \| `"status"` \| `"dataUpdatedAt"` \| `"errorUpdatedAt"` \| `"failureCount"` \| `"failureReason"` \| `"errorUpdateCount"` \| `"isFetched"` \| `"isFetchedAfterMount"` \| `"isFetching"` \| `"isInitialLoading"` \| `"isPaused"` \| `"isRefetching"` \| `"isStale"` \| `"isEnabled"` \| `"refetch"` \| `"fetchStatus"` \| `"fetchNextPage"` \| `"fetchPreviousPage"` \| `"hasNextPage"` \| `"hasPreviousPage"` \| `"isFetchNextPageError"` \| `"isFetchingNextPage"` \| `"isFetchPreviousPageError"` \| `"isFetchingPreviousPage"`)[] \| `undefined`) | `undefined` | If set, the component will only re-render if any of the listed properties change. When set to `['data', 'error']`, the component will only re-render when the `data` or `error` properties change. When set to `'all'`, the component will re-render whenever a query is updated. When set to a function, the function will be executed to compute the list of properties. Defaults to `undefined`, in which case property access is tracked automatically, and the component only re-renders when one of the tracked properties changes. |
-| `persister?` | (`queryFn`: (`context`: `object`) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>, `context`: `object`, `query`: [`Query`](../classes/Query.md)) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\> | `undefined` | This option can be used to persist the result of a query to an external storage, bypassing the need to actually call the `queryFn`. Useful for persisting a query's data across e.g. server/client boundaries. |
-| `placeholderData?` | \| `NonFunctionGuard`\<`TQueryFnData`\> \| ((`previousData`: `NonFunctionGuard`\<`TQueryFnData`\> \| `undefined`, `previousQuery`: \| [`Query`](../classes/Query.md)\<`NonFunctionGuard`\<`TQueryFnData`\>, `TError`, `NonFunctionGuard`\<`TQueryFnData`\>, `TQueryKey`\> \| `undefined`) => `NonFunctionGuard`\<`TQueryFnData`\> \| `undefined`) | `undefined` | If set, this value will be used as the placeholder data for this particular query observer while the query is still in the `loading` data and no initialData has been provided. |
-| `queryFn?` | \| *typeof* [`skipToken`](../variables/skipToken.md) \| ((`context`: `object`) => `TQueryFnData` \| `Promise`\<`TQueryFnData`\>) | `undefined` | The function that the query will use to request data. Required, unless a default query function has been set via `queryClient.setQueryDefaults` or `queryClient.setDefaultOptions`. Receives a [QueryFunctionContext](../type-aliases/QueryFunctionContext.md). Must return a promise that will either resolve data or throw an error. The data cannot be `undefined`. |
-| `queryHash?` | `string` | `undefined` | The hashed form of `queryKey`, computed with `queryKeyHashFn` (or the default hashing function otherwise). Used as the actual cache key internally. |
-| `queryKey` | `TQueryKey` & `object` | `undefined` | The query key to use for this query. The query key will be hashed into a stable hash. See [Query Keys](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for more information. The query will automatically update when this key changes (as long as `enabled` is not set to `false`). |
-| `queryKeyHashFn?` | (`queryKey`: `TQueryKey`) => `string` | `undefined` | If specified, this function is used to hash the `queryKey` to a string. |
-| `refetchInterval?` | \| `number` \| `false` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `number` \| `false` \| `undefined`) | `false` | If set to a number, the query will continuously refetch at this frequency in milliseconds. If set to a function, the function will be executed with the latest data and query to compute a frequency |
-| `refetchIntervalInBackground?` | `boolean` | `false` | If set to `true`, the query will continue to refetch while their tab/window is in the background. |
-| `refetchOnMount?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on mount if the data is stale. If set to `false`, will disable additional instances of a query to trigger background refetch. If set to `'always'`, the query will always refetch on mount (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value |
-| `refetchOnReconnect?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `undefined` | If set to `true`, the query will refetch on reconnect if the data is stale. If set to `false`, the query will not refetch on reconnect. If set to `'always'`, the query will always refetch on reconnect (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. Defaults to `true` unless `networkMode` is `'always'`. |
-| `refetchOnWindowFocus?` | \| `boolean` \| `"always"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean` \| `"always"`) | `true` | If set to `true`, the query will refetch on window focus if the data is stale. If set to `false`, the query will not refetch on window focus. If set to `'always'`, the query will always refetch on window focus (except when `staleTime: 'static'` is used). If set to a function, the function will be executed with the latest data and query to compute the value. |
-| `retry?` | \| `number` \| `false` \| `true` \| ((`failureCount`: `number`, `error`: `TError`) => `boolean`) | `undefined` | If `false`, failed queries will not retry by default. If `true`, failed queries will retry infinitely. If set to an integer number, e.g. 3, failed queries will retry until the failed query count meets that number. If set to a function `(failureCount, error) => boolean` failed queries will retry until the function returns false. Defaults to `3` on the client and `0` on the server. |
-| `retryDelay?` | `number` \| ((`failureCount`: `number`, `error`: `TError`) => `number`) | `undefined` | This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff. A function like `attempt => attempt * 1000` applies linear backoff. Defaults to a function that applies exponential backoff, capped at 30 seconds. |
-| `retryOnMount?` | \| `false` \| `true` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean`) | `true` | If set to `false`, the query will not be retried on mount if it contains an error. If set to a function, the function will be executed with the query to compute the value. |
-| `select?` | (`data`: `TQueryFnData`) => `TData` | `undefined` | This option can be used to transform or select a part of the data returned by the query function. It affects the returned `data` value, but does not affect what gets stored in the query cache. The `select` function will only run if `data` changed, or if the reference to the `select` function itself changes. To optimize, memoize the function so its reference stays stable across calls. |
-| `staleTime?` | \| `number` \| `"static"` \| ((`query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `number` \| `"static"`) | `0` | The time in milliseconds after data is considered stale. If set to `Infinity`, the data will never be considered stale. If set to `'static'`, the data will never be considered stale. If set to a function, the function will be executed with the query to compute a `staleTime`. |
-| `structuralSharing?` | `boolean` \| ((`oldData`: `unknown`, `newData`: `unknown`) => `unknown`) | `true` | Set this to `false` to disable structural sharing between query results. Set this to a function which accepts the old and new data and returns resolved data of the same type to implement custom structural sharing logic. |
-| `throwOnError?` | \| `false` \| `true` \| ((`error`: `TError`, `query`: [`Query`](../classes/Query.md)\<`TQueryFnData`, `TError`, `TQueryFnData`, `TQueryKey`\>) => `boolean`) | `false` | Whether errors should be thrown instead of setting the `error` property. If set to `true` or `suspense` is `true`, all errors will be thrown to the error boundary. If set to `false` and `suspense` is `false`, errors are returned as state. If set to a function, it will be passed the error and the query, and it should return a boolean indicating whether to show the error in an error boundary (`true`) or return the error as state (`false`). |
diff --git a/docs/framework/angular/reference/interfaces/DefinedInfiniteQueryNarrowing.md b/docs/framework/angular/reference/interfaces/DefinedInfiniteQueryNarrowing.md
new file mode 100644
index 00000000000..7af46858938
--- /dev/null
+++ b/docs/framework/angular/reference/interfaces/DefinedInfiniteQueryNarrowing.md
@@ -0,0 +1,28 @@
+---
+id: DefinedInfiniteQueryNarrowing
+title: DefinedInfiniteQueryNarrowing
+---
+
+
+
+Defined in: [packages/angular-query/src/types.ts:183](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L183)
+
+Signal-backed guards for a paginated query whose initial data excludes the pending state.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = [`DefaultError`](../type-aliases/DefaultError.md)
+
+## Properties
+
+| Property | Type | Description |
+| ------ | ------ | ------ |
+| `isError` | `SignalFunction`\<(`this`: [`DefinedCreateInfiniteQueryResult`](../type-aliases/DefinedCreateInfiniteQueryResult.md)\<`TData`, `TError`\>) => `this is DefinedCreateInfiniteQueryResult>`\> | Returns whether the result failed and narrows its data and error signals. |
+| `isPending` | `SignalFunction`\<(`this`: [`DefinedCreateInfiniteQueryResult`](../type-aliases/DefinedCreateInfiniteQueryResult.md)\<`TData`, `TError`\>) => `this is never`\> | Narrows the result to the pending state when that state is possible. |
+| `isSuccess` | `SignalFunction`\<(`this`: [`DefinedCreateInfiniteQueryResult`](../type-aliases/DefinedCreateInfiniteQueryResult.md)\<`TData`, `TError`\>) => `this is DefinedCreateInfiniteQueryResult>`\> | Returns whether the result is successful and narrows its data and error signals. |
diff --git a/docs/framework/angular/reference/interfaces/DefinedQueryNarrowing.md b/docs/framework/angular/reference/interfaces/DefinedQueryNarrowing.md
new file mode 100644
index 00000000000..af20e8d1d7d
--- /dev/null
+++ b/docs/framework/angular/reference/interfaces/DefinedQueryNarrowing.md
@@ -0,0 +1,28 @@
+---
+id: DefinedQueryNarrowing
+title: DefinedQueryNarrowing
+---
+
+
+
+Defined in: [packages/angular-query/src/types.ts:108](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L108)
+
+Signal-backed guards for a query whose initial data excludes the pending state.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = [`DefaultError`](../type-aliases/DefaultError.md)
+
+## Properties
+
+| Property | Type | Description |
+| ------ | ------ | ------ |
+| `isError` | `SignalFunction`\<() => `this is DefinedCreateQueryResult>`\> | Returns whether the result failed and narrows its data and error signals. |
+| `isPending` | `SignalFunction`\<() => `this is never`\> | Narrows the result to the pending state when that state is possible. |
+| `isSuccess` | `SignalFunction`\<() => `this is DefinedCreateQueryResult>`\> | Returns whether the result is successful and narrows its data and error signals. |
diff --git a/docs/framework/angular/reference/interfaces/InjectInfiniteQueryOptions.md b/docs/framework/angular/reference/interfaces/InjectInfiniteQueryOptions.md
deleted file mode 100644
index 909185a89b5..00000000000
--- a/docs/framework/angular/reference/interfaces/InjectInfiniteQueryOptions.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-id: InjectInfiniteQueryOptions
-title: InjectInfiniteQueryOptions
----
-
-
-
-Defined in: [packages/angular-query-experimental/src/inject-infinite-query.ts:29](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L29)
-
-Options for `injectInfiniteQuery`, passed after the function that returns the infinite
-query options.
-
-## Properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the infinite query. If this is not provided, the current injection context will be used instead (via `inject`). |
diff --git a/docs/framework/angular/reference/interfaces/InjectIsFetchingOptions.md b/docs/framework/angular/reference/interfaces/InjectIsFetchingOptions.md
deleted file mode 100644
index 91abb195fe9..00000000000
--- a/docs/framework/angular/reference/interfaces/InjectIsFetchingOptions.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-id: InjectIsFetchingOptions
-title: InjectIsFetchingOptions
----
-
-
-
-Defined in: [packages/angular-query-experimental/src/inject-is-fetching.ts:16](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-fetching.ts#L16)
-
-Options for `injectIsFetching`, passed after the query filters.
-
-## Properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the isFetching signal. If this is not provided, the current injection context will be used instead (via `inject`). |
diff --git a/docs/framework/angular/reference/interfaces/InjectIsMutatingOptions.md b/docs/framework/angular/reference/interfaces/InjectIsMutatingOptions.md
deleted file mode 100644
index a6949e57019..00000000000
--- a/docs/framework/angular/reference/interfaces/InjectIsMutatingOptions.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-id: InjectIsMutatingOptions
-title: InjectIsMutatingOptions
----
-
-
-
-Defined in: [packages/angular-query-experimental/src/inject-is-mutating.ts:16](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-mutating.ts#L16)
-
-Options for `injectIsMutating`, passed after the mutation filters.
-
-## Properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the isMutating signal. If this is not provided, the current injection context will be used instead (via `inject`). |
diff --git a/docs/framework/angular/reference/interfaces/InjectMutationOptions.md b/docs/framework/angular/reference/interfaces/InjectMutationOptions.md
deleted file mode 100644
index 3ce1d38c64e..00000000000
--- a/docs/framework/angular/reference/interfaces/InjectMutationOptions.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-id: InjectMutationOptions
-title: InjectMutationOptions
----
-
-
-
-Defined in: [packages/angular-query-experimental/src/inject-mutation.ts:31](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L31)
-
-Options for `injectMutation`, passed after the function that returns the mutation options.
-
-## Properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the mutation. If this is not provided, the current injection context will be used instead (via `inject`). |
diff --git a/docs/framework/angular/reference/interfaces/InjectMutationStateOptions.md b/docs/framework/angular/reference/interfaces/InjectMutationStateOptions.md
deleted file mode 100644
index b5c2bdf5c65..00000000000
--- a/docs/framework/angular/reference/interfaces/InjectMutationStateOptions.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-id: InjectMutationStateOptions
-title: InjectMutationStateOptions
----
-
-
-
-Defined in: [packages/angular-query-experimental/src/inject-mutation-state.ts:51](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation-state.ts#L51)
-
-Options for `injectMutationState`, passed after the function that returns the mutation state
-options.
-
-## Properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the mutation state signal. If this is not provided, the current injection context will be used instead (via `inject`). |
diff --git a/docs/framework/angular/reference/interfaces/InjectQueriesOptions.md b/docs/framework/angular/reference/interfaces/InjectQueriesOptions.md
new file mode 100644
index 00000000000..a2217dcf726
--- /dev/null
+++ b/docs/framework/angular/reference/interfaces/InjectQueriesOptions.md
@@ -0,0 +1,27 @@
+---
+id: InjectQueriesOptions
+title: InjectQueriesOptions
+---
+
+
+
+Defined in: [packages/angular-query/src/inject-queries.types.ts:226](https://github.com/TanStack/query/blob/main/packages/angular-query/src/inject-queries.types.ts#L226)
+
+A reactive group of query options and an optional projection of their combined results.
+
+## Type Parameters
+
+### T
+
+`T` *extends* `any`[]
+
+### TCombinedResult
+
+`TCombinedResult` = [`QueriesResults`](../type-aliases/QueriesResults.md)\<`T`\>
+
+## Properties
+
+| Property | Type | Description |
+| ------ | ------ | ------ |
+| `combine?` | (`result`: `T` *extends* \[\] ? \[\] : `T` *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<`Head`\>\[`"data"`\], [`QueryObserverResult`](../type-aliases/QueryObserverResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>, [`DefinedQueryObserverResult`](../type-aliases/DefinedQueryObserverResult.md)\<`InferDataAndError`\<`Head`\>\[`"data"`\], `InferDataAndError`\<`Head`\>\[`"error"`\]\>\>\] : `T` *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<...\>\[`"data"`\], [`QueryObserverResult`](../type-aliases/QueryObserverResult.md)\<...\[...\], ...\[...\]\>, [`DefinedQueryObserverResult`](../type-aliases/DefinedQueryObserverResult.md)\<...\[...\], ...\[...\]\>\>, `GenericGetDefinedOrUndefinedQueryResult`\<`Head`, `InferDataAndError`\<...\>\[`"data"`\], [`QueryObserverResult`](../type-aliases/QueryObserverResult.md)\<...\[...\], ...\[...\]\>, [`DefinedQueryObserverResult`](../type-aliases/DefinedQueryObserverResult.md)\<...\[...\], ...\[...\]\>\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...(...)[]`\] *extends* \[...\] ? \[..., ..., ...\] : ... *extends* ... ? ... : ... : \[...\{ \[K in (...) \| (...) \| (...)\]: GenericGetDefinedOrUndefinedQueryResult\<(...), (...), (...), (...)\> \}\[\]\] : \{ \[K in string \| number \| symbol\]: GenericGetDefinedOrUndefinedQueryResult\\["data"\], QueryObserverResult\\["data"\], InferDataAndError\<(...)\[(...)\]\>\["error"\]\>, DefinedQueryObserverResult\\["data"\], InferDataAndError\<(...)\[(...)\]\>\["error"\]\>\> \}) => `TCombinedResult` | Projects the current plain observer results into a single reactively computed value. |
+| `queries` | \| readonly \[\{ \[K in string \| number \| symbol\]: GetCreateQueryOptionsForCreateQueries\ \}\] \| readonly \[`T` *extends* \[\] ? \[\] : `T` *extends* \[`Head`\] ? \[`GetCreateQueryOptionsForCreateQueries`\<`Head`\>\] : `T` *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...Tails[]`\] *extends* \[`Head`\] ? \[`GetCreateQueryOptionsForCreateQueries`\<`Head`\>, `GetCreateQueryOptionsForCreateQueries`\<`Head`\>\] : \[`...Tails[]`\] *extends* \[`Head`, `...Tails[]`\] ? \[`...Tails[]`\] *extends* \[\] ? \[\] : \[`...(...)[]`\] *extends* \[...\] ? \[..., ..., ...\] : ... *extends* ... ? ... : ... : readonly `unknown`[] *extends* \[`...Tails[]`\] ? \[`...Tails[]`\] : \[`...(...)[]`\] *extends* ...[] ? ...[] : ...[] : readonly `unknown`[] *extends* `T` ? `T` : `T` *extends* `QueryObserverOptionsForCreateQueries`\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>[] ? `QueryObserverOptionsForCreateQueries`\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>[] : `QueryObserverOptionsForCreateQueries`\<`unknown`, `Error`, `unknown`, readonly `unknown`[]\>[]\] | The ordered query options to observe; entries can be added, removed, or replaced reactively. |
diff --git a/docs/framework/angular/reference/interfaces/InjectQueryOptions.md b/docs/framework/angular/reference/interfaces/InjectQueryOptions.md
deleted file mode 100644
index 80e4adabf20..00000000000
--- a/docs/framework/angular/reference/interfaces/InjectQueryOptions.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-id: InjectQueryOptions
-title: InjectQueryOptions
----
-
-
-
-Defined in: [packages/angular-query-experimental/src/inject-query.ts:23](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L23)
-
-Options for `injectQuery`, passed after the function that returns the query options.
-
-## Properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `injector?` | `Injector` | The `Injector` in which to create the query. If this is not provided, the current injection context will be used instead (via `inject`). |
diff --git a/docs/framework/angular/reference/interfaces/QueryFeature.md b/docs/framework/angular/reference/interfaces/QueryFeature.md
index 612359981e0..d488e6ac3f0 100644
--- a/docs/framework/angular/reference/interfaces/QueryFeature.md
+++ b/docs/framework/angular/reference/interfaces/QueryFeature.md
@@ -5,19 +5,7 @@ title: QueryFeature
-Defined in: [packages/angular-query-experimental/src/providers.ts:126](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L126)
+Defined in: [packages/angular-query/src/providers.ts:121](https://github.com/TanStack/query/blob/main/packages/angular-query/src/providers.ts#L121)
-Helper type to represent a Query feature.
-
-## Type Parameters
-
-### TFeatureKind
-
-`TFeatureKind` *extends* `QueryFeatureKind`
-
-## Properties
-
-| Property | Type | Description |
-| ------ | ------ | ------ |
-| `ɵkind` | `TFeatureKind` | The kind of the feature, e.g. `'Devtools'` or `'PersistQueryClient'`. |
-| `ɵproviders` | `Provider`[] | The providers that `provideTanStackQuery` registers for the feature. |
+Opaque configuration returned by Query feature functions such as `withHydrationKey`.
+Pass features to `provideTanStackQuery`; applications do not construct them directly.
diff --git a/docs/framework/angular/reference/interfaces/QueryObserverOptions.md b/docs/framework/angular/reference/interfaces/QueryObserverOptions.md
index 6a34e6e05cd..eb842bc6f56 100644
--- a/docs/framework/angular/reference/interfaces/QueryObserverOptions.md
+++ b/docs/framework/angular/reference/interfaces/QueryObserverOptions.md
@@ -18,7 +18,6 @@ The options of a `QueryObserver`, and of the hooks built on it like `useQuery`:
## Extended by
- [`InfiniteQueryObserverOptions`](InfiniteQueryObserverOptions.md)
-- [`CreateBaseQueryOptions`](CreateBaseQueryOptions.md)
## Type Parameters
diff --git a/docs/framework/angular/reference/interfaces/QueryResource.md b/docs/framework/angular/reference/interfaces/QueryResource.md
new file mode 100644
index 00000000000..516992c8037
--- /dev/null
+++ b/docs/framework/angular/reference/interfaces/QueryResource.md
@@ -0,0 +1,27 @@
+---
+id: QueryResource
+title: QueryResource
+---
+
+
+
+Defined in: [packages/angular-query/src/query-resource.ts:9](https://github.com/TanStack/query/blob/main/packages/angular-query/src/query-resource.ts#L9)
+
+A query-backed Angular Resource that also exposes an atomic state snapshot.
+
+## Extends
+
+- `Resource`\<`TValue`\>
+
+## Type Parameters
+
+### TValue
+
+`TValue`
+
+## Properties
+
+| Property | Modifier | Type | Description | Overrides |
+| ------ | ------ | ------ | ------ | ------ |
+| `reload` | `public` | () => `boolean` | Requests a new query fetch only when the current query data is stale. Used for compatibility with Angular APIs that might want to reload a resource, like Signal Forms' validateAsync resource interface. | - |
+| `snapshot` | `readonly` | `Signal`\<`ResourceSnapshot`\<`TValue`\>\> | The current query state as a single snapshot. | `Resource.snapshot` |
diff --git a/docs/framework/angular/reference/type-aliases/CreateBaseMutationResult.md b/docs/framework/angular/reference/type-aliases/CreateBaseMutationResult.md
index a419ba0c03e..29d15b617e3 100644
--- a/docs/framework/angular/reference/type-aliases/CreateBaseMutationResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateBaseMutationResult.md
@@ -11,7 +11,7 @@ type CreateBaseMutationResult & object;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:281](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L281)
+Defined in: [packages/angular-query/src/types.ts:389](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L389)
The pre-`Signal` shape [CreateMutationResult](CreateMutationResult.md) is built from — not what `injectMutation` actually
returns. Same as [MutationObserverResult](MutationObserverResult.md) from `@tanstack/query-core`, with `mutate` narrowed to the
diff --git a/docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md b/docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md
index 5e284d7ce79..492a5638948 100644
--- a/docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md
@@ -6,10 +6,10 @@ title: CreateBaseQueryResult
```ts
-type CreateBaseQueryResult> = BaseQueryNarrowing & MapToSignals>;
+type CreateBaseQueryResult = QueryObserverResult> = BaseQueryNarrowing & MapToSignals, QueryResultFields>;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:153](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L153)
+Defined in: [packages/angular-query/src/types.ts:249](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L249)
The result of `injectQuery` when `initialData` isn't set — `data` may be `undefined` while the query is
`pending`. Same shape as [QueryObserverResult](QueryObserverResult.md) from `@tanstack/query-core`, but value fields (like
@@ -34,4 +34,4 @@ The type of errors your `queryFn` may throw.
### TState
-`TState` = [`QueryObserverResult`](QueryObserverResult.md)\<`TData`, `TError`\>
+`TState` *extends* [`QueryObserverResult`](QueryObserverResult.md)\<`TData`, `TError`\> = [`QueryObserverResult`](QueryObserverResult.md)\<`TData`, `TError`\>
diff --git a/docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md b/docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md
index 64fe8bf7955..f1b973c6119 100644
--- a/docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md
@@ -6,10 +6,10 @@ title: CreateInfiniteQueryResult
```ts
-type CreateInfiniteQueryResult = BaseQueryNarrowing & MapToSignals>;
+type CreateInfiniteQueryResult = InfiniteQueryObserverResult> = BaseInfiniteQueryNarrowing & MapToSignals;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:192](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L192)
+Defined in: [packages/angular-query/src/types.ts:298](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L298)
The result of `injectInfiniteQuery` when `initialData` isn't set — `data` may be `undefined` while the
query is `pending`. Same shape as [InfiniteQueryObserverResult](InfiniteQueryObserverResult.md) from `@tanstack/query-core`, but
@@ -29,3 +29,7 @@ The type `data` ends up as after `select` runs.
`TError` = [`DefaultError`](DefaultError.md)
The type of errors your `queryFn` may throw.
+
+### TState
+
+`TState` *extends* [`InfiniteQueryObserverResult`](InfiniteQueryObserverResult.md)\<`TData`, `TError`\> = [`InfiniteQueryObserverResult`](InfiniteQueryObserverResult.md)\<`TData`, `TError`\>
diff --git a/docs/framework/angular/reference/type-aliases/CreateMutateAsyncFunction.md b/docs/framework/angular/reference/type-aliases/CreateMutateAsyncFunction.md
index 214d214bd29..81eece6fdf4 100644
--- a/docs/framework/angular/reference/type-aliases/CreateMutateAsyncFunction.md
+++ b/docs/framework/angular/reference/type-aliases/CreateMutateAsyncFunction.md
@@ -9,7 +9,7 @@ title: CreateMutateAsyncFunction
type CreateMutateAsyncFunction = MutateFunction;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:264](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L264)
+Defined in: [packages/angular-query/src/types.ts:372](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L372)
The type of `mutateAsync`, as returned by `injectMutation`. Similar to [CreateMutateFunction](CreateMutateFunction.md), but
returns a promise which can be awaited.
diff --git a/docs/framework/angular/reference/type-aliases/CreateMutateFunction.md b/docs/framework/angular/reference/type-aliases/CreateMutateFunction.md
index b40e164bd6b..5e3204ed8d8 100644
--- a/docs/framework/angular/reference/type-aliases/CreateMutateFunction.md
+++ b/docs/framework/angular/reference/type-aliases/CreateMutateFunction.md
@@ -9,12 +9,11 @@ title: CreateMutateFunction
type CreateMutateFunction = (...args: Parameters>) => void;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:244](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L244)
+Defined in: [packages/angular-query/src/types.ts:352](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L352)
The type of `mutate`, as returned by `injectMutation`. Forwards the variables (and an optional per-call
`onSuccess`/`onError`/`onSettled`) to the underlying `mutate` call. Fire-and-forget — errors are surfaced
-through the mutation result instead of being thrown by `mutate`, unless `throwOnError` makes
-`injectMutation` rethrow them after emitting them on `ngZone.onError`.
+through the mutation result, not thrown.
## Type Parameters
diff --git a/docs/framework/angular/reference/type-aliases/CreateMutationResult.md b/docs/framework/angular/reference/type-aliases/CreateMutationResult.md
index 3b4cccb4b48..09b883ac23a 100644
--- a/docs/framework/angular/reference/type-aliases/CreateMutationResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateMutationResult.md
@@ -6,10 +6,10 @@ title: CreateMutationResult
```ts
-type CreateMutationResult> = BaseMutationNarrowing & MapToSignals>;
+type CreateMutationResult> = BaseMutationNarrowing & MapToSignals, MutationResultFields>;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:423](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L423)
+Defined in: [packages/angular-query/src/types.ts:522](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L522)
The result of `injectMutation`. Based on [CreateBaseMutationResult](CreateBaseMutationResult.md), but value fields are exposed as
a `Signal` — read them with `mutation.data()`, not `mutation.data` — while function fields (`mutate`,
diff --git a/docs/framework/angular/reference/type-aliases/CreateQueryOptions.md b/docs/framework/angular/reference/type-aliases/CreateQueryOptions.md
new file mode 100644
index 00000000000..bbcc0b661f1
--- /dev/null
+++ b/docs/framework/angular/reference/type-aliases/CreateQueryOptions.md
@@ -0,0 +1,33 @@
+---
+id: CreateQueryOptions
+title: CreateQueryOptions
+---
+
+
+
+```ts
+type CreateQueryOptions = OmitKeyof, "notifyOnChangeProps" | "suspense" | "throwOnError">;
+```
+
+Defined in: [packages/angular-query/src/types.ts:32](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L32)
+
+Options accepted by `injectQuery`, with cache data projected through an optional `select`.
+Angular owns result notifications and exposes errors through signals rather than error boundaries.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = [`DefaultError`](DefaultError.md)
+
+### TData
+
+`TData` = `TQueryFnData`
+
+### TQueryKey
+
+`TQueryKey` *extends* [`QueryKey`](QueryKey.md) = [`QueryKey`](QueryKey.md)
diff --git a/docs/framework/angular/reference/type-aliases/CreateQueryResult.md b/docs/framework/angular/reference/type-aliases/CreateQueryResult.md
index 268f526443f..8451f99a8bb 100644
--- a/docs/framework/angular/reference/type-aliases/CreateQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/CreateQueryResult.md
@@ -9,7 +9,7 @@ title: CreateQueryResult
type CreateQueryResult = CreateBaseQueryResult;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:165](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L165)
+Defined in: [packages/angular-query/src/types.ts:267](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L267)
The result of `injectQuery`. Same as [CreateBaseQueryResult](CreateBaseQueryResult.md).
diff --git a/docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md b/docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md
index 58ef4a294d6..24bb39e57f2 100644
--- a/docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md
@@ -6,10 +6,10 @@ title: DefinedCreateInfiniteQueryResult
```ts
-type DefinedCreateInfiniteQueryResult> = MapToSignals;
+type DefinedCreateInfiniteQueryResult = DefinedInfiniteQueryObserverResult> = DefinedInfiniteQueryNarrowing & MapToSignals;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:205](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L205)
+Defined in: [packages/angular-query/src/types.ts:313](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L313)
The result of `injectInfiniteQuery` when `initialData` is set — `data` is never `undefined`. Same shape as
[DefinedInfiniteQueryObserverResult](DefinedInfiniteQueryObserverResult.md) from `@tanstack/query-core`, but value fields are exposed as a
@@ -31,4 +31,4 @@ The type of errors your `queryFn` may throw.
### TDefinedInfiniteQueryObserver
-`TDefinedInfiniteQueryObserver` = [`DefinedInfiniteQueryObserverResult`](DefinedInfiniteQueryObserverResult.md)\<`TData`, `TError`\>
+`TDefinedInfiniteQueryObserver` *extends* [`DefinedInfiniteQueryObserverResult`](DefinedInfiniteQueryObserverResult.md)\<`TData`, `TError`\> = [`DefinedInfiniteQueryObserverResult`](DefinedInfiniteQueryObserverResult.md)\<`TData`, `TError`\>
diff --git a/docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md b/docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md
index f235e5bdb44..85277c6fb62 100644
--- a/docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md
+++ b/docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md
@@ -6,10 +6,10 @@ title: DefinedCreateQueryResult
```ts
-type DefinedCreateQueryResult> = BaseQueryNarrowing & MapToSignals>;
+type DefinedCreateQueryResult = DefinedQueryObserverResult> = DefinedQueryNarrowing & MapToSignals, QueryResultFields>;
```
-Defined in: [packages/angular-query-experimental/src/types.ts:177](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L177)
+Defined in: [packages/angular-query/src/types.ts:279](https://github.com/TanStack/query/blob/main/packages/angular-query/src/types.ts#L279)
The result of `injectQuery` when `initialData` is set — `data` is never `undefined`. Same shape as
[DefinedQueryObserverResult](DefinedQueryObserverResult.md) from `@tanstack/query-core`, but value fields are exposed as a
@@ -31,4 +31,4 @@ The type of errors your `queryFn` may throw.
### TState
-`TState` = [`DefinedQueryObserverResult`](DefinedQueryObserverResult.md)\<`TData`, `TError`\>
+`TState` *extends* [`DefinedQueryObserverResult`](DefinedQueryObserverResult.md)\<`TData`, `TError`\> = [`DefinedQueryObserverResult`](DefinedQueryObserverResult.md)\<`TData`, `TError`\>
diff --git a/docs/framework/angular/reference/type-aliases/DefinedInitialDataInfiniteOptions.md b/docs/framework/angular/reference/type-aliases/DefinedInitialDataInfiniteOptions.md
index 59e9af3c26e..bec7095223b 100644
--- a/docs/framework/angular/reference/type-aliases/DefinedInitialDataInfiniteOptions.md
+++ b/docs/framework/angular/reference/type-aliases/DefinedInitialDataInfiniteOptions.md
@@ -9,7 +9,7 @@ title: DefinedInitialDataInfiniteOptions
type DefinedInitialDataInfiniteOptions, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown> = CreateInfiniteQueryOptions & object;
```
-Defined in: [packages/angular-query-experimental/src/infinite-query-options.ts:108](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L108)
+Defined in: [packages/angular-query/src/infinite-query-options.ts:108](https://github.com/TanStack/query/blob/main/packages/angular-query/src/infinite-query-options.ts#L108)
The options accepted by the `infiniteQueryOptions` overload selected when `initialData` is known to be
defined — `data` is never `undefined` (unless a `select` changes `TData` to include `undefined`).
diff --git a/docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md b/docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md
index 6d2f1de5847..891724254d7 100644
--- a/docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md
+++ b/docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md
@@ -6,10 +6,10 @@ title: DefinedInitialDataOptions
```ts
-type DefinedInitialDataOptions = Omit, "queryFn"> & object;
+type DefinedInitialDataOptions = CreateQueryOptions