### [Become a Sponsor!](https://github.com/sponsors/tannerlinsley/)
# TanStack Query
An async state management library built to simplify fetching, caching, synchronizing, and updating server state.
- Protocol‑agnostic fetching (REST, GraphQL, promises, etc.)
- Caching, refetching, pagination & infinite scroll
- Mutations, dependent queries & background updates
- Prefetching, cancellation & React Suspense support
### Read the docs →
## Get Involved
- We welcome issues and pull requests!
- Participate in [GitHub discussions](https://github.com/TanStack/query/discussions)
- Chat with the community on [Discord](https://discord.com/invite/WrRKjPJ)
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions
## Partners
We're looking for TanStack Query Partners to join our mission! Partner with us to push the boundaries of TanStack Query and build amazing things together.
## Explore the TanStack Ecosystem
- TanStack Config – Tooling for JS/TS packages
- TanStack DB – Reactive sync client store
- TanStack DevTools – Unified devtools panel
- TanStack Form – Type‑safe form state
- TanStack Pacer – Debouncing, throttling, batching
- TanStack Query – Async state & caching
- TanStack Ranger – Range & slider primitives
- TanStack Router – Type‑safe routing, caching & URL state
- TanStack Start – Full‑stack SSR & streaming
- TanStack Store – Reactive data store
- TanStack Table – Headless datagrids
- TanStack Virtual – Virtualized rendering
… and more at TanStack.com »
================================================
FILE: docs/community-resources.md
================================================
---
title: Community Resources
articles:
[
{
title: "TkDodo's Blog Posts",
url: 'https://tkdodo.eu/blog/practical-react-query',
description: 'TkDodo, a maintainer of TanStack Query, writes a series of blog posts about the library. These articles offer general best practices and often present opinionated perspectives on using TanStack Query.',
},
]
media:
[
{
title: 'React Query: It’s Time to Break up with your Global State! – Tanner Linsley',
url: 'https://www.youtube.com/watch?v=seU46c6Jz7E',
description: 'Get the lowdown on “global state” and how React Query can help you fetch, cache and manage your asynchronous data with a fraction of the effort and code that you’re used to',
},
{
title: 'All About React Query (with Tanner Linsley) — Learn With Jason',
url: 'https://www.youtube.com/watch?v=DocXo3gqGdI',
description: 'Learn all about React Query with its creator Tanner Linsley.',
},
{
title: 'Hooks for Fetching with ReactQuery Creator Tanner Linsley aka @tannerlinsley',
url: 'https://www.youtube.com/watch?v=PPvWXbSCtBU',
description: 'Learn how React Query simplifies asynchronous data fetching in React applications.',
},
{
title: 'React Query - Open Source Friday stream with Tanner Linsley from',
url: 'https://www.youtube.com/watch?v=B3cJDT3j19I',
description: 'An Open Source Friday stream featuring Tanner Linsley.',
},
{
title: 'React Query Presentation - Tanner Linsley',
url: 'https://www.youtube.com/watch?v=_ehibado6rU',
description: 'Tanner Linsley gives a talk to Lambda School students about the React Query.',
},
{
title: 'TanStack Query v4 (with Dominik Dorfmeister) — Learn With Jason',
url: 'https://www.youtube.com/watch?v=SPPQm0dvEes',
description: 'Dominik Dorfmeister covering TanStack Query v4.',
},
{
title: 'React Query Exposed by Its Maintainer',
url: 'https://www.youtube.com/watch?v=8-RTNnn9GR8',
description: 'Dominik Dorfmeister explores the less favorable aspects of React Query and situations where it may not be the best fit.',
},
{
title: 'React Query API Design: Lessons Learned - Dominik Dorfmeister',
url: 'https://www.youtube.com/watch?v=l3PxErcKeAI',
description: 'Dominik Dorfmeister walks through some of the API design choices that were made in React Query to get to the DX.',
},
]
utilities:
[
{
title: 'batshit',
url: 'https://github.com/yornaath/batshit',
description: 'A batch manager that will deduplicate and batch requests for a certain data type made within a window',
},
{
title: 'GraphQL Code Generator',
url: 'https://the-guild.dev/graphql/codegen',
description: 'Generate React Query hooks from your GraphQL schema',
},
{
title: 'Http-wizard',
url: 'https://http-wizard.com',
description: 'End-to-end type-safe Fastify API with typeScript magic ✨',
},
{
title: 'Normy',
url: 'https://github.com/klis87/normy',
description: 'Automatic normalization and data updates for data fetching libraries',
},
{
title: 'Orval',
url: 'https://orval.dev/',
description: 'Generate TypeScript client from OpenAPI specifications.',
},
{
title: 'Query Key Factory',
url: 'https://github.com/lukemorales/query-key-factory',
description: 'A library for creating typesafe standardized query keys, useful for cache management in @tanstack/query',
},
{
title: 'React Query Kit',
url: 'https://github.com/liaoliao666/react-query-kit',
description: '🕊️ A toolkit for ReactQuery that makes ReactQuery hooks reusable and typesafe',
},
{
title: 'React Query Rewind',
url: 'https://reactqueryrewind.com/',
description: 'Time travel and visualize state during development',
},
{
title: 'React Query Swagger',
url: 'https://github.com/Shaddix/react-query-swagger',
description: 'Generate React Query hooks based on Swagger API definitions',
},
{
title: 'Suspensive React Query',
url: 'https://suspensive.org/docs/react-query/motivation',
description: 'Enhances React Query with Suspense support, allowing for simpler and more declarative data fetching',
},
{
title: 'tRPC',
url: 'https://trpc.io/',
description: 'End-to-end typesafe APIs made easy',
},
]
others:
[
{
title: 'Atomic CRM',
url: 'https://marmelab.com/atomic-crm/',
description: 'A full-featured CRM built with React, react-admin, and Supabase.',
},
{
title: 'Blitz',
url: 'https://blitzjs.com/',
description: 'The Missing Fullstack Toolkit for Next.js',
},
{
title: 'Connect',
url: 'https://connectrpc.com/docs',
description: 'A family of libraries for building browser and gRPC-compatible HTTP APIs.',
},
{
title: 'Hey API',
url: 'https://heyapi.dev/openapi-ts/plugins/tanstack-query',
description: 'OpenAPI to TypeScript codegen. Production-ready SDKs, Zod schemas, TanStack Query hooks, and 20+ plugins. Used by Vercel, OpenCode, and PayPal.',
},
{
title: 'Kubb',
url: 'https://www.kubb.dev/',
description: 'Generate SDKs for all your APIs',
},
{
title: 'OpenAPI codegen',
url: 'https://github.com/fabien0102/openapi-codegen',
description: 'A tool for generating code based on an OpenAPI schema.',
},
{
title: 'OpenAPI Qraft React',
url: 'https://github.com/OpenAPI-Qraft/openapi-qraft',
description: 'Generate type-safe API clients and Hooks for TanStack Query directly from OpenAPI Documents.Zero-runtime overhead, Proxy-based design, seamless SSR support, and full TanStack Query functionality.',
},
{
title: 'OpenAPI React Query codegen',
url: 'https://github.com/7nohe/openapi-react-query-codegen',
description: 'Generate TanStack Query hooks based on an OpenAPI specification file.',
},
{
title: 'OpenAPI zod client',
url: 'https://github.com/astahmer/openapi-zod-client',
description: 'Generate a zodios client from an OpenAPI specification',
},
{
title: 'openapi-fetch',
url: 'https://openapi-ts.dev/openapi-react-query/',
description: 'A 2KB min, typesafe fetch wrapper that uses static TypeScript type inference and no runtime checks.',
},
{
title: 'oRPC',
url: 'https://orpc.unnoq.com/docs/integrations/tanstack-query',
description: 'Easy to build APIs that are end-to-end type-safe and adhere to OpenAPI standards.',
},
{
title: 'Rapini',
url: 'https://github.com/rametta/rapini',
description: '🥬 OpenAPI to React Query (or SWR) & Axios',
},
{
title: 'Tanstack Query Visualizer',
url: 'https://tanstack-query-visualizer.sofi.coop/',
description: 'An interactive sandbox that visualizes the relationship between mutations and query keys.',
},
{
title: 'ts-rest',
url: 'https://ts-rest.com/',
description: 'Incrementally adoptable type-safety for your new and existing APIs',
},
{
title: 'wagmi',
url: 'https://wagmi.sh/',
description: 'React Hooks for Ethereum based on @tanstack/react-query',
},
{
title: 'zodios',
url: 'https://www.zodios.org/',
description: 'End-to-end typesafe REST API toolbox',
},
]
---
================================================
FILE: docs/config.json
================================================
{
"$schema": "https://raw.githubusercontent.com/TanStack/tanstack.com/main/tanstack-docs-config.schema.json",
"docSearch": {
"appId": "20TOVD6LOE",
"apiKey": "35bc6c51aa322700d1383e17c4f669f4",
"indexName": "tanstackquery"
},
"sections": [
{
"label": "Community Resources",
"children": [],
"frameworks": []
},
{
"label": "Getting Started",
"children": [],
"frameworks": [
{
"label": "react",
"children": [
{
"label": "Overview",
"to": "framework/react/overview"
},
{
"label": "Installation",
"to": "framework/react/installation"
},
{
"label": "Quick Start",
"to": "framework/react/quick-start"
},
{
"label": "Devtools",
"to": "framework/react/devtools"
},
{
"label": "Comparison",
"to": "framework/react/comparison"
},
{
"label": "TypeScript",
"to": "framework/react/typescript"
},
{
"label": "GraphQL",
"to": "framework/react/graphql"
},
{
"label": "React Native",
"to": "framework/react/react-native"
}
]
},
{
"label": "solid",
"children": [
{
"label": "Overview",
"to": "framework/solid/overview"
},
{
"label": "Quick Start",
"to": "framework/solid/quick-start"
},
{
"label": "Installation",
"to": "framework/solid/installation"
},
{
"label": "Devtools",
"to": "framework/solid/devtools"
},
{
"label": "TypeScript",
"to": "framework/solid/typescript"
}
]
},
{
"label": "vue",
"children": [
{
"label": "Overview",
"to": "framework/vue/overview"
},
{
"label": "Installation",
"to": "framework/vue/installation"
},
{
"label": "Quick Start",
"to": "framework/vue/quick-start"
},
{
"label": "Devtools",
"to": "framework/vue/devtools"
},
{
"label": "TypeScript",
"to": "framework/vue/typescript"
},
{
"label": "Reactivity",
"to": "framework/vue/reactivity"
},
{
"label": "GraphQL",
"to": "framework/vue/graphql"
}
]
},
{
"label": "svelte",
"children": [
{
"label": "Overview",
"to": "framework/svelte/overview"
},
{
"label": "Installation",
"to": "framework/svelte/installation"
},
{
"label": "Devtools",
"to": "framework/svelte/devtools"
},
{
"label": "SSR & SvelteKit",
"to": "framework/svelte/ssr"
},
{
"label": "Migrate from v5 to v6",
"to": "framework/svelte/migrate-from-v5-to-v6"
}
]
},
{
"label": "angular",
"children": [
{
"label": "Overview",
"to": "framework/angular/overview"
},
{
"label": "Installation",
"to": "framework/angular/installation"
},
{
"label": "Quick Start",
"to": "framework/angular/quick-start"
},
{
"label": "Angular HttpClient and other data fetching clients",
"to": "framework/angular/angular-httpclient-and-other-data-fetching-clients"
},
{
"label": "Devtools",
"to": "framework/angular/devtools"
},
{
"label": "TypeScript",
"to": "framework/angular/typescript"
},
{
"label": "Zoneless",
"to": "framework/angular/zoneless"
}
]
},
{
"label": "preact",
"children": [
{
"label": "Overview",
"to": "framework/preact/overview"
},
{
"label": "Installation",
"to": "framework/preact/installation"
},
{
"label": "Quick Start",
"to": "framework/preact/quick-start"
},
{
"label": "Devtools",
"to": "framework/preact/devtools"
},
{
"label": "TypeScript",
"to": "framework/preact/typescript"
},
{
"label": "GraphQL",
"to": "framework/preact/graphql"
}
]
}
]
},
{
"label": "Guides & Concepts",
"children": [],
"frameworks": [
{
"label": "react",
"children": [
{
"label": "Important Defaults",
"to": "framework/react/guides/important-defaults"
},
{
"label": "Queries",
"to": "framework/react/guides/queries"
},
{
"label": "Query Keys",
"to": "framework/react/guides/query-keys"
},
{
"label": "Query Functions",
"to": "framework/react/guides/query-functions"
},
{
"label": "Query Options",
"to": "framework/react/guides/query-options"
},
{
"label": "Network Mode",
"to": "framework/react/guides/network-mode"
},
{
"label": "Parallel Queries",
"to": "framework/react/guides/parallel-queries"
},
{
"label": "Dependent Queries",
"to": "framework/react/guides/dependent-queries"
},
{
"label": "Background Fetching Indicators",
"to": "framework/react/guides/background-fetching-indicators"
},
{
"label": "Window Focus Refetching",
"to": "framework/react/guides/window-focus-refetching"
},
{
"label": "Disabling/Pausing Queries",
"to": "framework/react/guides/disabling-queries"
},
{
"label": "Query Retries",
"to": "framework/react/guides/query-retries"
},
{
"label": "Paginated Queries",
"to": "framework/react/guides/paginated-queries"
},
{
"label": "Infinite Queries",
"to": "framework/react/guides/infinite-queries"
},
{
"label": "Initial Query Data",
"to": "framework/react/guides/initial-query-data"
},
{
"label": "Placeholder Query Data",
"to": "framework/react/guides/placeholder-query-data"
},
{
"label": "Mutations",
"to": "framework/react/guides/mutations"
},
{
"label": "Query Invalidation",
"to": "framework/react/guides/query-invalidation"
},
{
"label": "Invalidation from Mutations",
"to": "framework/react/guides/invalidations-from-mutations"
},
{
"label": "Updates from Mutation Responses",
"to": "framework/react/guides/updates-from-mutation-responses"
},
{
"label": "Optimistic Updates",
"to": "framework/react/guides/optimistic-updates"
},
{
"label": "Query Cancellation",
"to": "framework/react/guides/query-cancellation"
},
{
"label": "Scroll Restoration",
"to": "framework/react/guides/scroll-restoration"
},
{
"label": "Filters",
"to": "framework/react/guides/filters"
},
{
"label": "Performance & Request Waterfalls",
"to": "framework/react/guides/request-waterfalls"
},
{
"label": "Prefetching & Router Integration",
"to": "framework/react/guides/prefetching"
},
{
"label": "Server Rendering & Hydration",
"to": "framework/react/guides/ssr"
},
{
"label": "Advanced Server Rendering",
"to": "framework/react/guides/advanced-ssr"
},
{
"label": "Caching",
"to": "framework/react/guides/caching"
},
{
"label": "Render Optimizations",
"to": "framework/react/guides/render-optimizations"
},
{
"label": "Default Query Fn",
"to": "framework/react/guides/default-query-function"
},
{
"label": "Suspense",
"to": "framework/react/guides/suspense"
},
{
"label": "Testing",
"to": "framework/react/guides/testing"
},
{
"label": "Does this replace [Redux, MobX, etc]?",
"to": "framework/react/guides/does-this-replace-client-state"
},
{
"label": "Migrating to v3",
"to": "framework/react/guides/migrating-to-react-query-3"
},
{
"label": "Migrating to v4",
"to": "framework/react/guides/migrating-to-react-query-4"
},
{
"label": "Migrating to v5",
"to": "framework/react/guides/migrating-to-v5"
}
]
},
{
"label": "solid",
"children": [
{
"label": "Important Defaults",
"to": "framework/solid/guides/important-defaults"
},
{
"label": "Queries",
"to": "framework/solid/guides/queries"
},
{
"label": "Query Keys",
"to": "framework/solid/guides/query-keys"
},
{
"label": "Query Functions",
"to": "framework/solid/guides/query-functions"
},
{
"label": "Query Options",
"to": "framework/solid/guides/query-options"
},
{
"label": "Network Mode",
"to": "framework/solid/guides/network-mode"
},
{
"label": "Parallel Queries",
"to": "framework/solid/guides/parallel-queries"
},
{
"label": "Dependent Queries",
"to": "framework/solid/guides/dependent-queries"
},
{
"label": "Background Fetching Indicators",
"to": "framework/solid/guides/background-fetching-indicators"
},
{
"label": "Window Focus Refetching",
"to": "framework/solid/guides/window-focus-refetching"
},
{
"label": "Disabling/Pausing Queries",
"to": "framework/solid/guides/disabling-queries"
},
{
"label": "Query Retries",
"to": "framework/solid/guides/query-retries"
},
{
"label": "Paginated Queries",
"to": "framework/solid/guides/paginated-queries"
},
{
"label": "Infinite Queries",
"to": "framework/solid/guides/infinite-queries"
},
{
"label": "Initial Query Data",
"to": "framework/solid/guides/initial-query-data"
},
{
"label": "Placeholder Query Data",
"to": "framework/solid/guides/placeholder-query-data"
},
{
"label": "Mutations",
"to": "framework/solid/guides/mutations"
},
{
"label": "Query Invalidation",
"to": "framework/solid/guides/query-invalidation"
},
{
"label": "Invalidation from Mutations",
"to": "framework/solid/guides/invalidations-from-mutations"
},
{
"label": "Updates from Mutation Responses",
"to": "framework/solid/guides/updates-from-mutation-responses"
},
{
"label": "Optimistic Updates",
"to": "framework/solid/guides/optimistic-updates"
},
{
"label": "Query Cancellation",
"to": "framework/solid/guides/query-cancellation"
},
{
"label": "Scroll Restoration",
"to": "framework/solid/guides/scroll-restoration"
},
{
"label": "Filters",
"to": "framework/solid/guides/filters"
},
{
"label": "Request Waterfalls",
"to": "framework/solid/guides/request-waterfalls"
},
{
"label": "Prefetching",
"to": "framework/solid/guides/prefetching"
},
{
"label": "SSR",
"to": "framework/solid/guides/ssr"
},
{
"label": "Advanced SSR",
"to": "framework/solid/guides/advanced-ssr"
},
{
"label": "Caching",
"to": "framework/solid/guides/caching"
},
{
"label": "Default Query Fn",
"to": "framework/solid/guides/default-query-function"
},
{
"label": "Suspense",
"to": "framework/solid/guides/suspense"
},
{
"label": "Testing",
"to": "framework/solid/guides/testing"
},
{
"label": "Does this replace state managers?",
"to": "framework/solid/guides/does-this-replace-client-state"
}
]
},
{
"label": "vue",
"children": [
{
"label": "Important Defaults",
"to": "framework/vue/guides/important-defaults"
},
{
"label": "Queries",
"to": "framework/vue/guides/queries"
},
{
"label": "Query Keys",
"to": "framework/vue/guides/query-keys"
},
{
"label": "Query Functions",
"to": "framework/vue/guides/query-functions"
},
{
"label": "Query Options",
"to": "framework/vue/guides/query-options"
},
{
"label": "Network Mode",
"to": "framework/vue/guides/network-mode"
},
{
"label": "Parallel Queries",
"to": "framework/vue/guides/parallel-queries"
},
{
"label": "Dependent Queries",
"to": "framework/vue/guides/dependent-queries"
},
{
"label": "Background Fetching Indicators",
"to": "framework/vue/guides/background-fetching-indicators"
},
{
"label": "Window Focus Refetching",
"to": "framework/vue/guides/window-focus-refetching"
},
{
"label": "Disabling/Pausing Queries",
"to": "framework/vue/guides/disabling-queries"
},
{
"label": "Query Retries",
"to": "framework/vue/guides/query-retries"
},
{
"label": "Paginated Queries",
"to": "framework/vue/guides/paginated-queries"
},
{
"label": "Infinite Queries",
"to": "framework/vue/guides/infinite-queries"
},
{
"label": "Initial Query Data",
"to": "framework/vue/guides/initial-query-data"
},
{
"label": "Placeholder Query Data",
"to": "framework/vue/guides/placeholder-query-data"
},
{
"label": "Mutations",
"to": "framework/vue/guides/mutations"
},
{
"label": "Query Invalidation",
"to": "framework/vue/guides/query-invalidation"
},
{
"label": "Invalidation from Mutations",
"to": "framework/vue/guides/invalidations-from-mutations"
},
{
"label": "Updates from Mutation Responses",
"to": "framework/vue/guides/updates-from-mutation-responses"
},
{
"label": "Optimistic Updates",
"to": "framework/vue/guides/optimistic-updates"
},
{
"label": "Query Cancellation",
"to": "framework/vue/guides/query-cancellation"
},
{
"label": "Scroll Restoration",
"to": "framework/vue/guides/scroll-restoration"
},
{
"label": "Filters",
"to": "framework/vue/guides/filters"
},
{
"label": "Prefetching",
"to": "framework/vue/guides/prefetching"
},
{
"label": "SSR & Nuxt",
"to": "framework/vue/guides/ssr"
},
{
"label": "Caching",
"to": "framework/vue/guides/caching"
},
{
"label": "Default Query Fn",
"to": "framework/vue/guides/default-query-function"
},
{
"label": "Suspense",
"to": "framework/vue/guides/suspense"
},
{
"label": "Testing",
"to": "framework/vue/guides/testing"
},
{
"label": "Custom Client",
"to": "framework/vue/guides/custom-client"
},
{
"label": "Does this replace [Vuex, Pinia]?",
"to": "framework/vue/guides/does-this-replace-client-state"
},
{
"label": "Migrating to v5",
"to": "framework/vue/guides/migrating-to-v5"
}
]
},
{
"label": "angular",
"children": [
{
"label": "Important Defaults",
"to": "framework/angular/guides/important-defaults"
},
{
"label": "Queries",
"to": "framework/angular/guides/queries"
},
{
"label": "Query Keys",
"to": "framework/angular/guides/query-keys"
},
{
"label": "Query Functions",
"to": "framework/angular/guides/query-functions"
},
{
"label": "Query Options",
"to": "framework/angular/guides/query-options"
},
{
"label": "Network Mode",
"to": "framework/angular/guides/network-mode"
},
{
"label": "Parallel Queries",
"to": "framework/angular/guides/parallel-queries"
},
{
"label": "Dependent Queries",
"to": "framework/angular/guides/dependent-queries"
},
{
"label": "Background Fetching Indicators",
"to": "framework/angular/guides/background-fetching-indicators"
},
{
"label": "Window Focus Refetching",
"to": "framework/angular/guides/window-focus-refetching"
},
{
"label": "Disabling/Pausing Queries",
"to": "framework/angular/guides/disabling-queries"
},
{
"label": "Query Retries",
"to": "framework/angular/guides/query-retries"
},
{
"label": "Paginated Queries",
"to": "framework/angular/guides/paginated-queries"
},
{
"label": "Infinite Queries",
"to": "framework/angular/guides/infinite-queries"
},
{
"label": "Initial Query Data",
"to": "framework/angular/guides/initial-query-data"
},
{
"label": "Placeholder Query Data",
"to": "framework/angular/guides/placeholder-query-data"
},
{
"label": "Mutations",
"to": "framework/angular/guides/mutations"
},
{
"label": "Mutation Options",
"to": "framework/angular/guides/mutation-options"
},
{
"label": "Query Invalidation",
"to": "framework/angular/guides/query-invalidation"
},
{
"label": "Invalidation from Mutations",
"to": "framework/angular/guides/invalidations-from-mutations"
},
{
"label": "Optimistic Updates",
"to": "framework/angular/guides/optimistic-updates"
},
{
"label": "Query Cancellation",
"to": "framework/angular/guides/query-cancellation"
},
{
"label": "Scroll Restoration",
"to": "framework/angular/guides/scroll-restoration"
},
{
"label": "Filters",
"to": "framework/angular/guides/filters"
},
{
"label": "Caching",
"to": "framework/angular/guides/caching"
},
{
"label": "Default Query Fn",
"to": "framework/angular/guides/default-query-function"
},
{
"label": "Testing",
"to": "framework/angular/guides/testing"
},
{
"label": "Does this replace state managers?",
"to": "framework/angular/guides/does-this-replace-client-state"
}
]
},
{
"label": "preact",
"children": [
{
"label": "Important Defaults",
"to": "framework/preact/guides/important-defaults"
},
{
"label": "Queries",
"to": "framework/preact/guides/queries"
},
{
"label": "Query Keys",
"to": "framework/preact/guides/query-keys"
},
{
"label": "Query Functions",
"to": "framework/preact/guides/query-functions"
},
{
"label": "Query Options",
"to": "framework/preact/guides/query-options"
},
{
"label": "Network Mode",
"to": "framework/preact/guides/network-mode"
},
{
"label": "Parallel Queries",
"to": "framework/preact/guides/parallel-queries"
},
{
"label": "Dependent Queries",
"to": "framework/preact/guides/dependent-queries"
},
{
"label": "Background Fetching Indicators",
"to": "framework/preact/guides/background-fetching-indicators"
},
{
"label": "Window Focus Refetching",
"to": "framework/preact/guides/window-focus-refetching"
},
{
"label": "Disabling/Pausing Queries",
"to": "framework/preact/guides/disabling-queries"
},
{
"label": "Query Retries",
"to": "framework/preact/guides/query-retries"
},
{
"label": "Paginated Queries",
"to": "framework/preact/guides/paginated-queries"
},
{
"label": "Infinite Queries",
"to": "framework/preact/guides/infinite-queries"
},
{
"label": "Initial Query Data",
"to": "framework/preact/guides/initial-query-data"
},
{
"label": "Placeholder Query Data",
"to": "framework/preact/guides/placeholder-query-data"
},
{
"label": "Mutations",
"to": "framework/preact/guides/mutations"
},
{
"label": "Query Invalidation",
"to": "framework/preact/guides/query-invalidation"
},
{
"label": "Invalidation from Mutations",
"to": "framework/preact/guides/invalidations-from-mutations"
},
{
"label": "Updates from Mutation Responses",
"to": "framework/preact/guides/updates-from-mutation-responses"
},
{
"label": "Optimistic Updates",
"to": "framework/preact/guides/optimistic-updates"
},
{
"label": "Query Cancellation",
"to": "framework/preact/guides/query-cancellation"
},
{
"label": "Scroll Restoration",
"to": "framework/preact/guides/scroll-restoration"
},
{
"label": "Filters",
"to": "framework/preact/guides/filters"
},
{
"label": "Performance & Request Waterfalls",
"to": "framework/preact/guides/request-waterfalls"
},
{
"label": "Prefetching & Router Integration",
"to": "framework/preact/guides/prefetching"
},
{
"label": "Caching",
"to": "framework/preact/guides/caching"
},
{
"label": "Render Optimizations",
"to": "framework/preact/guides/render-optimizations"
},
{
"label": "Default Query Fn",
"to": "framework/preact/guides/default-query-function"
},
{
"label": "Does this replace [Redux, MobX, etc]?",
"to": "framework/preact/guides/does-this-replace-client-state"
}
]
}
]
},
{
"label": "API Reference",
"children": [
{
"label": "QueryClient",
"to": "reference/QueryClient"
},
{
"label": "QueryCache",
"to": "reference/QueryCache"
},
{
"label": "MutationCache",
"to": "reference/MutationCache"
},
{
"label": "QueryObserver",
"to": "reference/QueryObserver"
},
{
"label": "InfiniteQueryObserver",
"to": "reference/InfiniteQueryObserver"
},
{
"label": "QueriesObserver",
"to": "reference/QueriesObserver"
},
{
"label": "streamedQuery",
"to": "reference/streamedQuery"
},
{
"label": "focusManager",
"to": "reference/focusManager"
},
{
"label": "onlineManager",
"to": "reference/onlineManager"
},
{
"label": "environmentManager",
"to": "reference/environmentManager"
},
{
"label": "notifyManager",
"to": "reference/notifyManager"
},
{
"label": "timeoutManager",
"to": "reference/timeoutManager"
}
],
"frameworks": [
{
"label": "react",
"children": [
{
"label": "useQuery",
"to": "framework/react/reference/useQuery"
},
{
"label": "useQueries",
"to": "framework/react/reference/useQueries"
},
{
"label": "useInfiniteQuery",
"to": "framework/react/reference/useInfiniteQuery"
},
{
"label": "useMutation",
"to": "framework/react/reference/useMutation"
},
{
"label": "useIsFetching",
"to": "framework/react/reference/useIsFetching"
},
{
"label": "useIsMutating",
"to": "framework/react/reference/useIsMutating"
},
{
"label": "useMutationState",
"to": "framework/react/reference/useMutationState"
},
{
"label": "useSuspenseQuery",
"to": "framework/react/reference/useSuspenseQuery"
},
{
"label": "useSuspenseInfiniteQuery",
"to": "framework/react/reference/useSuspenseInfiniteQuery"
},
{
"label": "useSuspenseQueries",
"to": "framework/react/reference/useSuspenseQueries"
},
{
"label": "QueryClientProvider",
"to": "framework/react/reference/QueryClientProvider"
},
{
"label": "useQueryClient",
"to": "framework/react/reference/useQueryClient"
},
{
"label": "queryOptions",
"to": "framework/react/reference/queryOptions"
},
{
"label": "infiniteQueryOptions",
"to": "framework/react/reference/infiniteQueryOptions"
},
{
"label": "mutationOptions",
"to": "framework/react/reference/mutationOptions"
},
{
"label": "usePrefetchQuery",
"to": "framework/react/reference/usePrefetchQuery"
},
{
"label": "usePrefetchInfiniteQuery",
"to": "framework/react/reference/usePrefetchInfiniteQuery"
},
{
"label": "QueryErrorResetBoundary",
"to": "framework/react/reference/QueryErrorResetBoundary"
},
{
"label": "useQueryErrorResetBoundary",
"to": "framework/react/reference/useQueryErrorResetBoundary"
},
{
"label": "hydration",
"to": "framework/react/reference/hydration"
}
]
},
{
"label": "vue",
"children": [
{
"label": "useQuery",
"to": "framework/vue/reference/useQuery"
},
{
"label": "useQueries",
"to": "framework/vue/reference/useQueries"
},
{
"label": "useInfiniteQuery",
"to": "framework/vue/reference/useInfiniteQuery"
},
{
"label": "useMutation",
"to": "framework/vue/reference/useMutation"
},
{
"label": "useIsFetching",
"to": "framework/vue/reference/useIsFetching"
},
{
"label": "useIsMutating",
"to": "framework/vue/reference/useIsMutating"
},
{
"label": "useMutationState",
"to": "framework/vue/reference/useMutationState"
},
{
"label": "useQueryClient",
"to": "framework/vue/reference/useQueryClient"
},
{
"label": "queryOptions",
"to": "framework/vue/reference/queryOptions"
},
{
"label": "infiniteQueryOptions",
"to": "framework/vue/reference/infiniteQueryOptions"
},
{
"label": "hydration",
"to": "framework/vue/reference/hydration"
}
]
},
{
"label": "solid",
"children": [
{
"label": "useQuery",
"to": "framework/solid/reference/useQuery"
},
{
"label": "useQueries",
"to": "framework/solid/reference/useQueries"
},
{
"label": "useInfiniteQuery",
"to": "framework/solid/reference/useInfiniteQuery"
},
{
"label": "useMutation",
"to": "framework/solid/reference/useMutation"
},
{
"label": "useIsFetching",
"to": "framework/solid/reference/useIsFetching"
},
{
"label": "useIsMutating",
"to": "framework/solid/reference/useIsMutating"
},
{
"label": "useMutationState",
"to": "framework/solid/reference/useMutationState"
},
{
"label": "queryOptions",
"to": "framework/solid/reference/queryOptions"
},
{
"label": "infiniteQueryOptions",
"to": "framework/solid/reference/infiniteQueryOptions"
},
{
"label": "hydration",
"to": "framework/solid/reference/hydration"
}
]
},
{
"label": "svelte",
"children": [
{
"label": "Svelte Reference",
"to": "framework/svelte/reference/index"
},
{
"label": "Functions / createQuery",
"to": "framework/svelte/reference/functions/createQuery"
},
{
"label": "Functions / createQueries",
"to": "framework/svelte/reference/functions/createQueries"
},
{
"label": "Functions / createInfiniteQuery",
"to": "framework/svelte/reference/functions/createInfiniteQuery"
},
{
"label": "Functions / createMutation",
"to": "framework/svelte/reference/functions/createMutation"
},
{
"label": "Functions / useIsFetching",
"to": "framework/svelte/reference/functions/useIsFetching"
},
{
"label": "Functions / useIsMutating",
"to": "framework/svelte/reference/functions/useIsMutating"
},
{
"label": "Functions / useMutationState",
"to": "framework/svelte/reference/functions/useMutationState"
},
{
"label": "Functions / queryOptions",
"to": "framework/svelte/reference/functions/queryOptions"
},
{
"label": "Functions / infiniteQueryOptions",
"to": "framework/svelte/reference/functions/infiniteQueryOptions"
},
{
"label": "Functions / mutationOptions",
"to": "framework/svelte/reference/functions/mutationOptions"
}
]
},
{
"label": "angular",
"children": [
{
"label": "Angular Reference",
"to": "framework/angular/reference/index"
},
{
"label": "Functions / injectQuery",
"to": "framework/angular/reference/functions/injectQuery"
},
{
"label": "Functions / injectMutation",
"to": "framework/angular/reference/functions/injectMutation"
}
]
},
{
"label": "preact",
"children": [
{
"label": "useQuery",
"to": "framework/preact/reference/functions/useQuery"
},
{
"label": "useQueries",
"to": "framework/preact/reference/functions/useQueries"
},
{
"label": "useInfiniteQuery",
"to": "framework/preact/reference/functions/useInfiniteQuery"
},
{
"label": "useMutation",
"to": "framework/preact/reference/functions/useMutation"
},
{
"label": "useIsFetching",
"to": "framework/preact/reference/functions/useIsFetching"
},
{
"label": "useIsMutating",
"to": "framework/preact/reference/functions/useIsMutating"
},
{
"label": "useMutationState",
"to": "framework/preact/reference/functions/useMutationState"
},
{
"label": "useSuspenseQuery",
"to": "framework/preact/reference/functions/useSuspenseQuery"
},
{
"label": "useSuspenseInfiniteQuery",
"to": "framework/preact/reference/functions/useSuspenseInfiniteQuery"
},
{
"label": "useSuspenseQueries",
"to": "framework/preact/reference/functions/useSuspenseQueries"
},
{
"label": "QueryClientProvider",
"to": "framework/preact/reference/functions/QueryClientProvider"
},
{
"label": "useQueryClient",
"to": "framework/preact/reference/functions/useQueryClient"
},
{
"label": "queryOptions",
"to": "framework/preact/reference/functions/queryOptions"
},
{
"label": "infiniteQueryOptions",
"to": "framework/preact/reference/functions/infiniteQueryOptions"
},
{
"label": "mutationOptions",
"to": "framework/preact/reference/functions/mutationOptions"
},
{
"label": "usePrefetchQuery",
"to": "framework/preact/reference/functions/usePrefetchQuery"
},
{
"label": "usePrefetchInfiniteQuery",
"to": "framework/preact/reference/functions/usePrefetchInfiniteQuery"
},
{
"label": "QueryErrorResetBoundary",
"to": "framework/preact/reference/functions/QueryErrorResetBoundary"
},
{
"label": "useQueryErrorResetBoundary",
"to": "framework/preact/reference/functions/useQueryErrorResetBoundary"
},
{
"label": "hydration",
"to": "framework/preact/reference/functions/HydrationBoundary"
}
]
}
]
},
{
"label": "ESLint",
"children": [
{
"label": "ESLint Plugin Query",
"to": "eslint/eslint-plugin-query"
},
{
"label": "Exhaustive Deps",
"to": "eslint/exhaustive-deps"
},
{
"label": "Stable Query Client",
"to": "eslint/stable-query-client"
},
{
"label": "No Rest Destructuring",
"to": "eslint/no-rest-destructuring"
},
{
"label": "No Unstable Deps",
"to": "eslint/no-unstable-deps"
},
{
"label": "Infinite Query Property Order",
"to": "eslint/infinite-query-property-order"
},
{
"label": "No void Query Functions",
"to": "eslint/no-void-query-fn"
},
{
"label": "Mutation Property Order",
"to": "eslint/mutation-property-order"
}
]
},
{
"label": "Examples",
"children": [],
"frameworks": [
{
"label": "react",
"children": [
{
"label": "Simple",
"to": "framework/react/examples/simple"
},
{
"label": "Basic",
"to": "framework/react/examples/basic"
},
{
"label": "Basic w/ GraphQL-Request",
"to": "framework/react/examples/basic-graphql-request"
},
{
"label": "Auto Refetching / Polling / Realtime",
"to": "framework/react/examples/auto-refetching"
},
{
"label": "Optimistic Updates (UI)",
"to": "framework/react/examples/optimistic-updates-ui"
},
{
"label": "Optimistic Updates (Cache)",
"to": "framework/react/examples/optimistic-updates-cache"
},
{
"label": "Pagination",
"to": "framework/react/examples/pagination"
},
{
"label": "Load-More & Infinite Scroll",
"to": "framework/react/examples/load-more-infinite-scroll"
},
{
"label": "Infinite query with Max pages",
"to": "framework/react/examples/infinite-query-with-max-pages"
},
{
"label": "Suspense",
"to": "framework/react/examples/suspense"
},
{
"label": "Default Query Function",
"to": "framework/react/examples/default-query-function"
},
{
"label": "Playground",
"to": "framework/react/examples/playground"
},
{
"label": "Prefetching",
"to": "framework/react/examples/prefetching"
},
{
"label": "Star Wars",
"to": "framework/react/examples/star-wars"
},
{
"label": "Rick And Morty",
"to": "framework/react/examples/rick-morty"
},
{
"label": "Next.js Pages",
"to": "framework/react/examples/nextjs"
},
{
"label": "Next.js app with prefetching",
"to": "framework/react/examples/nextjs-app-prefetching"
},
{
"label": "Next.js app with streaming",
"to": "framework/react/examples/nextjs-suspense-streaming"
},
{
"label": "React Native",
"to": "framework/react/examples/react-native"
},
{
"label": "React Router",
"to": "framework/react/examples/react-router"
},
{
"label": "Offline Queries and Mutations",
"to": "framework/react/examples/offline"
},
{
"label": "Algolia",
"to": "framework/react/examples/algolia"
},
{
"label": "Shadow DOM",
"to": "framework/react/examples/shadow-dom"
},
{
"label": "Devtools Embedded Panel",
"to": "framework/react/examples/devtools-panel"
},
{
"label": "Chat example (streaming)",
"to": "framework/react/examples/chat"
}
]
},
{
"label": "solid",
"children": [
{
"label": "Simple",
"to": "framework/solid/examples/simple"
},
{
"label": "Basic",
"to": "framework/solid/examples/basic"
},
{
"label": "Basic w/ GraphQL-Request",
"to": "framework/solid/examples/basic-graphql-request"
},
{
"label": "Default Query Function",
"to": "framework/solid/examples/default-query-function"
},
{
"label": "Solid Start",
"to": "framework/solid/examples/solid-start-streaming"
},
{
"label": "Astro",
"to": "framework/solid/examples/astro"
},
{
"label": "Offline Queries and Mutations",
"to": "framework/solid/examples/offline"
}
]
},
{
"label": "vue",
"children": [
{
"label": "Basic",
"to": "framework/vue/examples/basic"
},
{
"label": "Vue 2.6",
"to": "framework/vue/examples/2.6-basic"
},
{
"label": "Vue 2.7",
"to": "framework/vue/examples/2.7-basic"
},
{
"label": "Nuxt 3",
"to": "framework/vue/examples/nuxt3"
},
{
"label": "Persister",
"to": "framework/vue/examples/persister"
}
]
},
{
"label": "svelte",
"children": [
{
"label": "Simple",
"to": "framework/svelte/examples/simple"
},
{
"label": "Basic",
"to": "framework/svelte/examples/basic"
},
{
"label": "Auto Refetching / Polling / Realtime",
"to": "framework/svelte/examples/auto-refetching"
},
{
"label": "SSR",
"to": "framework/svelte/examples/ssr"
},
{
"label": "Optimistic Updates",
"to": "framework/svelte/examples/optimistic-updates"
},
{
"label": "Playground",
"to": "framework/svelte/examples/playground"
},
{
"label": "Star Wars",
"to": "framework/svelte/examples/star-wars"
},
{
"label": "Infinite Queries",
"to": "framework/svelte/examples/load-more-infinite-scroll"
}
]
},
{
"label": "angular",
"children": [
{
"label": "Simple",
"to": "framework/angular/examples/simple"
},
{
"label": "Basic",
"to": "framework/angular/examples/basic"
},
{
"label": "Auto Refetching / Polling / Realtime",
"to": "framework/angular/examples/auto-refetching"
},
{
"label": "Optimistic Updates",
"to": "framework/angular/examples/optimistic-updates"
},
{
"label": "Pagination",
"to": "framework/angular/examples/pagination"
},
{
"label": "Infinite query with maxPages",
"to": "framework/angular/examples/infinite-query-with-max-pages"
},
{
"label": "Angular Router",
"to": "framework/angular/examples/router"
},
{
"label": "RxJS autocomplete",
"to": "framework/angular/examples/rxjs"
},
{
"label": "Query options from a service",
"to": "framework/angular/examples/query-options-from-a-service"
},
{
"label": "Devtools embedded panel",
"to": "framework/angular/examples/devtools-panel"
}
]
}
]
},
{
"label": "Plugins",
"children": [],
"frameworks": [
{
"label": "react",
"children": [
{
"label": "persistQueryClient",
"to": "framework/react/plugins/persistQueryClient"
},
{
"label": "createSyncStoragePersister",
"to": "framework/react/plugins/createSyncStoragePersister"
},
{
"label": "createAsyncStoragePersister",
"to": "framework/react/plugins/createAsyncStoragePersister"
},
{
"label": "broadcastQueryClient (Experimental)",
"to": "framework/react/plugins/broadcastQueryClient"
},
{
"label": "createPersister (Experimental)",
"to": "framework/react/plugins/createPersister"
}
]
},
{
"label": "solid",
"children": [
{
"label": "broadcastQueryClient (Experimental)",
"to": "framework/solid/plugins/broadcastQueryClient"
},
{
"label": "createPersister (Experimental)",
"to": "framework/solid/plugins/createPersister"
}
]
},
{
"label": "vue",
"children": [
{
"label": "broadcastQueryClient (Experimental)",
"to": "framework/vue/plugins/broadcastQueryClient"
},
{
"label": "createPersister (Experimental)",
"to": "framework/vue/plugins/createPersister"
}
]
},
{
"label": "preact",
"children": [
{
"label": "persistQueryClient",
"to": "framework/preact/plugins/persistQueryClient"
},
{
"label": "createSyncStoragePersister",
"to": "framework/preact/plugins/createSyncStoragePersister"
},
{
"label": "createAsyncStoragePersister",
"to": "framework/preact/plugins/createAsyncStoragePersister"
},
{
"label": "broadcastQueryClient (Experimental)",
"to": "framework/preact/plugins/broadcastQueryClient"
},
{
"label": "createPersister (Experimental)",
"to": "framework/preact/plugins/createPersister"
}
]
}
]
}
],
"users": [
"Google",
"Walmart",
"Facebook",
"PayPal",
"Amazon",
"American Express",
"Microsoft",
"Target",
"Ebay",
"Autodesk",
"CarFAX",
"Docusign",
"HP",
"MLB",
"Volvo",
"Ocado",
"UPC.ch",
"EFI.com",
"ReactBricks",
"Nozzle.io",
"Uber"
]
}
================================================
FILE: docs/eslint/eslint-plugin-query.md
================================================
---
id: eslint-plugin-query
title: ESLint Plugin Query
---
TanStack Query comes with its own ESLint plugin. This plugin is used to enforce best practices and to help you avoid common mistakes.
## Installation
The plugin is a separate package that you need to install:
```bash
npm i -D @tanstack/eslint-plugin-query
```
or
```bash
pnpm add -D @tanstack/eslint-plugin-query
```
or
```bash
yarn add -D @tanstack/eslint-plugin-query
```
or
```bash
bun add -D @tanstack/eslint-plugin-query
```
## Flat Config (`eslint.config.js`)
### Recommended setup
To enable all of the recommended rules for our plugin, add the following config:
```js
import pluginQuery from '@tanstack/eslint-plugin-query'
export default [
...pluginQuery.configs['flat/recommended'],
// Any other config...
]
```
### Custom setup
Alternatively, you can load the plugin and configure only the rules you want to use:
```js
import pluginQuery from '@tanstack/eslint-plugin-query'
export default [
{
plugins: {
'@tanstack/query': pluginQuery,
},
rules: {
'@tanstack/query/exhaustive-deps': 'error',
},
},
// Any other config...
]
```
## Legacy Config (`.eslintrc`)
### Recommended setup
To enable all of the recommended rules for our plugin, add `plugin:@tanstack/query/recommended` in extends:
```json
{
"extends": ["plugin:@tanstack/query/recommended"]
}
```
### Custom setup
Alternatively, add `@tanstack/query` to the plugins section, and configure the rules you want to use:
```json
{
"plugins": ["@tanstack/query"],
"rules": {
"@tanstack/query/exhaustive-deps": "error"
}
}
```
## Rules
- [@tanstack/query/exhaustive-deps](./exhaustive-deps.md)
- [@tanstack/query/no-rest-destructuring](./no-rest-destructuring.md)
- [@tanstack/query/stable-query-client](./stable-query-client.md)
- [@tanstack/query/no-unstable-deps](./no-unstable-deps.md)
- [@tanstack/query/infinite-query-property-order](./infinite-query-property-order.md)
- [@tanstack/query/no-void-query-fn](./no-void-query-fn.md)
- [@tanstack/query/mutation-property-order](./mutation-property-order.md)
================================================
FILE: docs/eslint/exhaustive-deps.md
================================================
---
id: exhaustive-deps
title: Exhaustive dependencies for query keys
---
Query keys should be seen like a dependency array to your query function: Every variable that is used inside the queryFn should be added to the query key.
This makes sure that queries are cached independently and that queries are refetched automatically when the variables changes.
## Rule Details
Examples of **incorrect** code for this rule:
```tsx
/* eslint "@tanstack/query/exhaustive-deps": "error" */
useQuery({
queryKey: ['todo'],
queryFn: () => api.getTodo(todoId),
})
const todoQueries = {
detail: (id) => ({ queryKey: ['todo'], queryFn: () => api.getTodo(id) }),
}
```
Examples of **correct** code for this rule:
```tsx
useQuery({
queryKey: ['todo', todoId],
queryFn: () => api.getTodo(todoId),
})
const todoQueries = {
detail: (id) => ({ queryKey: ['todo', id], queryFn: () => api.getTodo(id) }),
}
```
## When Not To Use It
If you don't care about the rules of the query keys, then you will not need this rule.
## Attributes
- [x] ✅ Recommended
- [x] 🔧 Fixable
================================================
FILE: docs/eslint/infinite-query-property-order.md
================================================
---
id: infinite-query-property-order
title: Ensure correct order of inference sensitive properties for infinite queries
---
For the following functions, the property order of the passed in object matters due to type inference:
- `useInfiniteQuery`
- `useSuspenseInfiniteQuery`
- `infiniteQueryOptions`
The correct property order is as follows:
- `queryFn`
- `getPreviousPageParam`
- `getNextPageParam`
All other properties are insensitive to the order as they do not depend on type inference.
## Rule Details
Examples of **incorrect** code for this rule:
```tsx
/* eslint "@tanstack/query/infinite-query-property-order": "warn" */
import { useInfiniteQuery } from '@tanstack/react-query'
const query = useInfiniteQuery({
queryKey: ['projects'],
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
queryFn: async ({ pageParam }) => {
const response = await fetch(`/api/projects?cursor=${pageParam}`)
return await response.json()
},
initialPageParam: 0,
getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
maxPages: 3,
})
```
Examples of **correct** code for this rule:
```tsx
/* eslint "@tanstack/query/infinite-query-property-order": "warn" */
import { useInfiniteQuery } from '@tanstack/react-query'
const query = useInfiniteQuery({
queryKey: ['projects'],
queryFn: async ({ pageParam }) => {
const response = await fetch(`/api/projects?cursor=${pageParam}`)
return await response.json()
},
initialPageParam: 0,
getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
maxPages: 3,
})
```
## Attributes
- [x] ✅ Recommended
- [x] 🔧 Fixable
================================================
FILE: docs/eslint/mutation-property-order.md
================================================
---
id: mutation-property-order
title: Ensure correct order of inference-sensitive properties in useMutation()
---
For the following functions, the property order of the passed in object matters due to type inference:
- `useMutation()`
The correct property order is as follows:
- `onMutate`
- `onError`
- `onSettled`
All other properties are insensitive to the order as they do not depend on type inference.
## Rule Details
Examples of **incorrect** code for this rule:
```tsx
/* eslint "@tanstack/query/mutation-property-order": "warn" */
import { useMutation } from '@tanstack/react-query'
const mutation = useMutation({
mutationFn: () => Promise.resolve('success'),
onSettled: () => {
results.push('onSettled-promise')
return Promise.resolve('also-ignored') // Promise (should be ignored)
},
onMutate: async () => {
results.push('onMutate-async')
await sleep(1)
return { backup: 'async-data' }
},
onError: async () => {
results.push('onError-async-start')
await sleep(1)
results.push('onError-async-end')
},
})
```
Examples of **correct** code for this rule:
```tsx
/* eslint "@tanstack/query/mutation-property-order": "warn" */
import { useMutation } from '@tanstack/react-query'
const mutation = useMutation({
mutationFn: () => Promise.resolve('success'),
onMutate: async () => {
results.push('onMutate-async')
await sleep(1)
return { backup: 'async-data' }
},
onError: async () => {
results.push('onError-async-start')
await sleep(1)
results.push('onError-async-end')
},
onSettled: () => {
results.push('onSettled-promise')
return Promise.resolve('also-ignored') // Promise (should be ignored)
},
})
```
## Attributes
- [x] ✅ Recommended
- [x] 🔧 Fixable
================================================
FILE: docs/eslint/no-rest-destructuring.md
================================================
---
id: no-rest-destructuring
title: Disallow object rest destructuring on query results
---
Use object rest destructuring on query results automatically subscribes to every field of the query result, which may cause unnecessary re-renders.
This makes sure that you only subscribe to the fields that you actually need.
## Rule Details
Examples of **incorrect** code for this rule:
```tsx
/* eslint "@tanstack/query/no-rest-destructuring": "warn" */
const useTodos = () => {
const { data: todos, ...rest } = useQuery({
queryKey: ['todos'],
queryFn: () => api.getTodos(),
})
return { todos, ...rest }
}
```
Examples of **correct** code for this rule:
```tsx
const todosQuery = useQuery({
queryKey: ['todos'],
queryFn: () => api.getTodos(),
})
// normal object destructuring is fine
const { data: todos } = todosQuery
```
## When Not To Use It
If you set the `notifyOnChangeProps` options manually, you can disable this rule.
Since you are not using tracked queries, you are responsible for specifying which props should trigger a re-render.
## Attributes
- [x] ✅ Recommended
- [ ] 🔧 Fixable
================================================
FILE: docs/eslint/no-unstable-deps.md
================================================
---
id: no-unstable-deps
title: Disallow putting the result of query hooks directly in a React hook dependency array
---
The object returned from the following query hooks is **not** referentially stable:
- `useQuery`
- `useSuspenseQuery`
- `useQueries`
- `useSuspenseQueries`
- `useInfiniteQuery`
- `useSuspenseInfiniteQuery`
- `useMutation`
The object returned from those hooks should **not** be put directly into the dependency array of a React hook (e.g. `useEffect`, `useMemo`, `useCallback`).
Instead, destructure the return value of the query hook and pass the destructured values into the dependency array of the React hook.
## Rule Details
Examples of **incorrect** code for this rule:
```tsx
/* eslint "@tanstack/query/no-unstable-deps": "warn" */
import { useCallback } from 'React'
import { useMutation } from '@tanstack/react-query'
function Component() {
const mutation = useMutation({ mutationFn: (value: string) => value })
const callback = useCallback(() => {
mutation.mutate('hello')
}, [mutation])
return null
}
```
Examples of **correct** code for this rule:
```tsx
/* eslint "@tanstack/query/no-unstable-deps": "warn" */
import { useCallback } from 'React'
import { useMutation } from '@tanstack/react-query'
function Component() {
const { mutate } = useMutation({ mutationFn: (value: string) => value })
const callback = useCallback(() => {
mutate('hello')
}, [mutate])
return null
}
```
## Attributes
- [x] ✅ Recommended
- [ ] 🔧 Fixable
================================================
FILE: docs/eslint/no-void-query-fn.md
================================================
---
id: no-void-query-fn
title: Disallow returning void from query functions
---
Query functions must return a value that will be cached by TanStack Query. Functions that don't return a value (void functions) can lead to unexpected behavior and might indicate a mistake in the implementation.
## Rule Details
Example of **incorrect** code for this rule:
```tsx
/* eslint "@tanstack/query/no-void-query-fn": "error" */
useQuery({
queryKey: ['todos'],
queryFn: async () => {
await api.todos.fetch() // Function doesn't return the fetched data
},
})
```
Example of **correct** code for this rule:
```tsx
/* eslint "@tanstack/query/no-void-query-fn": "error" */
useQuery({
queryKey: ['todos'],
queryFn: async () => {
const todos = await api.todos.fetch()
return todos
},
})
```
## Attributes
- [x] ✅ Recommended
- [ ] 🔧 Fixable
================================================
FILE: docs/eslint/stable-query-client.md
================================================
---
id: stable-query-client
title: Stable Query Client
---
The QueryClient contains the QueryCache, so you'd only want to create one instance of the QueryClient for the lifecycle of your application - _not_ a new instance on every render.
> Exception: It's allowed to create a new QueryClient inside an async Server Component, because the async function is only called once on the server.
## Rule Details
Examples of **incorrect** code for this rule:
```tsx
/* eslint "@tanstack/query/stable-query-client": "error" */
function App() {
const queryClient = new QueryClient()
return (
)
}
```
Examples of **correct** code for this rule:
```tsx
function App() {
const [queryClient] = useState(() => new QueryClient())
return (
)
}
```
```tsx
const queryClient = new QueryClient()
function App() {
return (
)
}
```
```tsx
async function App() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery(options)
}
```
## Attributes
- [x] ✅ Recommended
- [x] 🔧 Fixable
================================================
FILE: docs/framework/angular/angular-httpclient-and-other-data-fetching-clients.md
================================================
---
id: Angular-HttpClient-and-other-data-fetching-clients
title: Angular HttpClient and other data fetching clients
---
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.
## Using Angular's `HttpClient` for data fetching
`HttpClient` is a powerful and integrated part of Angular, which gives the following benefits:
- 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`.
```ts
@Component({
// ...
})
class ExampleComponent {
private readonly http = inject(HttpClient)
readonly query = injectQuery(() => ({
queryKey: ['repoData'],
queryFn: () =>
lastValueFrom(
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.
## Comparison table
| 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. |
================================================
FILE: docs/framework/angular/devtools.md
================================================
---
id: devtools
title: Devtools
---
> For Chrome, Firefox, and Edge users: Third-party browser extensions are available for debugging TanStack Query directly in browser DevTools. These provide the same functionality as the framework-specific devtools packages:
>
> - [Devtools for Chrome](https://chromewebstore.google.com/detail/tanstack-query-devtools/annajfchloimdhceglpgglpeepfghfai)
> - [Devtools for Firefox](https://addons.mozilla.org/en-US/firefox/addon/tanstack-query-devtools/)
> - [Devtools for Edge](https://microsoftedge.microsoft.com/addons/detail/tanstack-query-devtools/edmdpkgkacmjopodhfolmphdenmddobj)
## Enable 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.
```ts
import {
QueryClient,
provideTanStackQuery,
} from '@tanstack/angular-query-experimental'
import { withDevtools } from '@tanstack/angular-query-experimental/devtools'
export const appConfig: ApplicationConfig = {
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.
```ts
import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
```
To control when devtools are loaded, you can 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.
```ts
import { withDevtools } from '@tanstack/angular-query-experimental/devtools'
provideTanStackQuery(new QueryClient(), withDevtools())
// which is equivalent to
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: 'auto' })),
)
```
When setting the option to true, the devtools will be loaded 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'
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: environment.loadDevtools })),
)
```
When setting the option to false, the devtools will not be loaded.
```ts
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: false })),
)
```
## Derive options through reactivity
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.
The example below always loads devtools in development mode and loads on-demand in production mode when a keyboard shortcut is pressed.
```ts
import { Injectable, isDevMode } from '@angular/core'
import { fromEvent, map, scan } from 'rxjs'
import { toSignal } from '@angular/core/rxjs-interop'
@Injectable({ providedIn: 'root' })
export class DevtoolsOptionsManager {
loadDevtools = toSignal(
fromEvent(document, 'keydown').pipe(
map(
(event): boolean =>
event.metaKey && event.ctrlKey && event.shiftKey && event.key === 'D',
),
scan((acc, curr) => acc || curr, isDevMode()),
),
{
initialValue: isDevMode(),
},
)
}
```
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.
```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'
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],
},
),
),
],
}
```
### Options returned from the callback
Of these options `loadDevtools`, `client`, `position`, `errorTypes`, `buttonPosition`, and `initialIsOpen` support reactivity through 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.
- `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"`
- Defaults to `bottom-right`
- The position of the TanStack logo to open and close the devtools panel
- If `relative`, the button is placed in the location that you render the devtools.
- `position?: "top" | "bottom" | "left" | "right"`
- Defaults to `bottom`
- The position of the Angular Query devtools panel
- `client?: QueryClient`,
- Use this to use a custom QueryClient. Otherwise, the QueryClient provided through `provideTanStackQuery` will be injected.
- `errorTypes?: { name: string; initializer: (query: Query) => TError}[]`
- Use this to predefine some errors that can be triggered on your queries. Initializer will be called (with the specific query) when that error is toggled on from the UI. It must return an Error.
- `styleNonce?: string`
- Use this to pass a nonce to the style tag that is added to the document head. This is useful if you are using a Content Security Policy (CSP) nonce to allow inline styles.
- `shadowDOMTarget?: ShadowRoot`
- Default behavior will apply the devtool's styles to the head tag within the DOM.
- Use this to pass a shadow DOM target to the devtools so that the styles will be applied within the shadow DOM instead of within the head tag in the light DOM.
- `hideDisabledQueries?: boolean`
- Set this to true to hide disabled queries from the devtools panel.
================================================
FILE: docs/framework/angular/guides/background-fetching-indicators.md
================================================
---
id: background-fetching-indicators
title: Background Fetching Indicators
ref: docs/framework/react/guides/background-fetching-indicators.md
replace:
{
'useIsFetching': 'injectIsFetching',
'hook': 'function',
'@tanstack/react-query': '@tanstack/angular-query-experimental',
}
---
[//]: # 'Example'
```angular-ts
@Component({
selector: 'todos',
template: `
@if (todosQuery.isPending()) {
Loading...
} @else if (todosQuery.isError()) {
An error has occurred: {{ todosQuery.error().message }}
} @else if (todosQuery.isSuccess()) {
@if (todosQuery.isFetching()) {
Refreshing...
}
@for (todos of todosQuery.data(); track todo.id) {
}
}
`,
})
class TodosComponent {
todosQuery = injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodos,
}))
}
```
[//]: # 'Example'
[//]: # 'Example2'
```angular-ts
import { injectIsFetching } from '@tanstack/angular-query-experimental'
@Component({
selector: 'global-loading-indicator',
template: `
@if (isFetching()) {
Queries are fetching in the background...
}
`,
})
export class GlobalLoadingIndicatorComponent {
isFetching = injectIsFetching()
}
```
[//]: # 'Example2'
================================================
FILE: docs/framework/angular/guides/caching.md
================================================
---
id: caching
title: Caching Examples
---
> Please thoroughly read the [Important Defaults](./important-defaults.md) before reading this guide
## Basic Example
This caching example illustrates the story and lifecycle of:
- Query Instances with and without cache data
- Background Refetching
- Inactive Queries
- Garbage Collection
Let's assume we are using the default `gcTime` of **5 minutes** and the default `staleTime` of `0`.
- A new instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos }))` initializes.
- Since no other queries have been made with the `['todos']` query key, this query will show a hard loading state and make a network request to fetch the data.
- When the network request has completed, the returned data will be cached under the `['todos']` key.
- The data will be marked as stale after the configured `staleTime` (defaults to `0`, or immediately).
- A second instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos }))` initializes elsewhere.
- Since the cache already has data for the `['todos']` key from the first query, that data is immediately returned from the cache.
- The new instance triggers a new network request using its query function.
- Note that regardless of whether both `fetchTodos` query functions are identical or not, both queries' [`status`](../reference/functions/injectQuery.md) are updated (including `isFetching`, `isPending`, and other related values) because they have the same query key.
- When the request completes successfully, the cache's data under the `['todos']` key is updated with the new data, and both instances are updated with the new data.
- Both instances of the `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos }))` query are destroyed and no longer in use.
- Since there are no more active instances of this query, a garbage collection timeout is set using `gcTime` to delete and garbage collect the query (defaults to **5 minutes**).
- Before the cache timeout has completed, another instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos }))` mounts. The query immediately returns the available cached data while the `fetchTodos` function is being run in the background. When it completes successfully, it will populate the cache with fresh data.
- The final instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos }))` gets destroyed.
- No more instances of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos }))` appear within **5 minutes**.
- The cached data under the `['todos']` key is deleted and garbage collected.
For more advanced use-cases, see [injectQuery](../reference/functions/injectQuery.md).
================================================
FILE: docs/framework/angular/guides/default-query-function.md
================================================
---
id: default-query-function
title: Default Query Function
ref: docs/framework/react/guides/default-query-function.md
---
[//]: # 'Example'
```ts
// Define a default query function that will receive the query key
const defaultQueryFn: QueryFunction = async ({ queryKey }) => {
const { data } = await axios.get(
`https://jsonplaceholder.typicode.com${queryKey[0]}`,
)
return data
}
// provide the default query function to your app with defaultOptions
const queryClient = new QueryClient({
defaultOptions: {
queries: {
queryFn: defaultQueryFn,
},
},
})
bootstrapApplication(MyAppComponent, {
providers: [provideTanStackQuery(queryClient)],
})
export class PostsComponent {
// All you have to do now is pass a key!
postsQuery = injectQuery>(() => ({
queryKey: ['/posts'],
}))
// ...
}
export class PostComponent {
// You can even leave out the queryFn and just go straight into options
postQuery = injectQuery(() => ({
enabled: this.postIdSignal() > 0,
queryKey: [`/posts/${this.postIdSignal()}`],
}))
// ...
}
```
[//]: # 'Example'
================================================
FILE: docs/framework/angular/guides/dependent-queries.md
================================================
---
id: dependent-queries
title: Dependent Queries
ref: docs/framework/react/guides/dependent-queries.md
replace: { 'useQuery': 'injectQuery', 'useQueries': 'injectQueries' }
---
[//]: # 'Example'
```ts
// Get the user
userQuery = injectQuery(() => ({
queryKey: ['user', email],
queryFn: getUserByEmail,
}))
// Then get the user's projects
projectsQuery = injectQuery(() => ({
queryKey: ['projects', this.userQuery.data()?.id],
queryFn: getProjectsByUser,
// The query will not execute until the user id exists
enabled: !!this.userQuery.data()?.id,
}))
```
[//]: # 'Example'
[//]: # 'Example2'
```ts
// injectQueries is under development for Angular Query
```
[//]: # 'Example2'
================================================
FILE: docs/framework/angular/guides/disabling-queries.md
================================================
---
id: disabling-queries
title: Disabling/Pausing Queries
ref: docs/framework/react/guides/disabling-queries.md
replace: { 'useQuery': 'injectQuery' }
---
[//]: # 'Example'
```angular-ts
@Component({
selector: 'todos',
template: `
@if (query.data()) {
@for (todo of query.data(); track todo.id) {
{{ todo.title }}
}
} @else {
@if (query.isError()) {
Error: {{ query.error().message }}
} @else if (query.isLoading()) {
Loading...
} @else if (!query.isLoading() && !query.isError()) {
Not ready ...
}
}
}
`,
})
class TodosComponent {}
```
[//]: # 'ExampleUI3'
[//]: # 'ExampleUI4'
```ts
// somewhere in your app
addTodo = injectMutation(() => ({
mutationFn: (newTodo: string) => axios.post('/api/data', { text: newTodo }),
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
mutationKey: ['addTodo'],
}))
// access variables somewhere else
mutationState = injectMutationState(() => ({
filters: { mutationKey: ['addTodo'], status: 'pending' },
select: (mutation) => mutation.state.variables,
}))
```
[//]: # 'ExampleUI4'
[//]: # 'Example'
```ts
queryClient = inject(QueryClient)
updateTodo = injectMutation(() => ({
mutationFn: updateTodo,
// When mutate is called:
onMutate: async (newTodo, context) => {
// Cancel any outgoing refetches
// (so they don't overwrite our optimistic update)
await context.client.cancelQueries({ queryKey: ['todos'] })
// Snapshot the previous value
const previousTodos = context.client.getQueryData(['todos'])
// Optimistically update to the new value
context.client.setQueryData(['todos'], (old) => [...old, newTodo])
// Return a result object with the snapshotted value
return { previousTodos }
},
// If the mutation fails,
// use the result returned from onMutate to roll back
onError: (err, newTodo, onMutateResult, context) => {
context.client.setQueryData(['todos'], onMutateResult.previousTodos)
},
// Always refetch after error or success:
onSettled: (data, error, variables, onMutateResult, context) => {
context.client.invalidateQueries({ queryKey: ['todos'] })
},
}))
```
[//]: # 'Example'
[//]: # 'Example2'
```ts
queryClient = inject(QueryClient)
updateTodo = injectMutation(() => ({
mutationFn: updateTodo,
// When mutate is called:
onMutate: async (newTodo, context) => {
// Cancel any outgoing refetches
// (so they don't overwrite our optimistic update)
await context.client.cancelQueries({ queryKey: ['todos', newTodo.id] })
// Snapshot the previous value
const previousTodo = context.client.getQueryData(['todos', newTodo.id])
// Optimistically update to the new value
context.client.setQueryData(['todos', newTodo.id], newTodo)
// Return a result with the previous and new todo
return { previousTodo, newTodo }
},
// If the mutation fails, use the result we returned above
onError: (err, newTodo, onMutateResult, context) => {
context.client.setQueryData(
['todos', onMutateResult.newTodo.id],
onMutateResult.previousTodo,
)
},
// Always refetch after error or success:
onSettled: (newTodo, error, variables, onMutateResult, context) => {
context.client.invalidateQueries({ queryKey: ['todos', newTodo.id] })
},
}))
```
[//]: # 'Example2'
[//]: # 'Example3'
```ts
injectMutation({
mutationFn: updateTodo,
// ...
onSettled: (newTodo, error, variables, onMutateResult, context) => {
if (error) {
// do something
}
},
})
```
[//]: # 'Example3'
================================================
FILE: docs/framework/angular/guides/paginated-queries.md
================================================
---
id: paginated-queries
title: Paginated / Lagged Queries
ref: docs/framework/react/guides/paginated-queries.md
replace:
{
'useQuery': 'injectQuery',
'useInfiniteQuery': 'injectInfiniteQuery',
'hook': 'function',
}
---
[//]: # 'Example'
```ts
const result = injectQuery(() => ({
queryKey: ['projects', page()],
queryFn: fetchProjects,
}))
```
[//]: # 'Example'
[//]: # 'Example2'
```angular-ts
@Component({
selector: 'pagination-example',
template: `
In this example, each page of data remains visible as the next page is
fetched. The buttons and capability to proceed to the next page are also
suppressed until the next page cursor is known. Each page is cached as a
normal query too, so when going to previous pages, you'll see them
instantaneously while they are also re-fetched invisibly in the
background.
@if (query.status() === 'pending') {
Loading...
} @else if (query.status() === 'error') {
Error: {{ query.error().message }}
} @else {
@for (project of query.data().projects; track project.id) {
{{ project.name }}
}
}
Current Page: {{ page() + 1 }}
@if (query.isFetching()) {
Loading...
}
`,
})
export class PaginationExampleComponent {
page = signal(0)
#queryClient = inject(QueryClient)
query = injectQuery(() => ({
queryKey: ['projects', this.page()],
queryFn: () => lastValueFrom(fetchProjects(this.page())),
placeholderData: keepPreviousData,
staleTime: 5000,
}))
constructor() {
effect(() => {
// Prefetch the next page!
if (!this.query.isPlaceholderData() && this.query.data()?.hasMore) {
this.#queryClient.prefetchQuery({
queryKey: ['projects', this.page() + 1],
queryFn: () => lastValueFrom(fetchProjects(this.page() + 1)),
})
}
})
}
previousPage() {
this.page.update((old) => Math.max(old - 1, 0))
}
nextPage() {
this.page.update((old) => (this.query.data()?.hasMore ? old + 1 : old))
}
}
```
[//]: # 'Example2'
================================================
FILE: docs/framework/angular/guides/parallel-queries.md
================================================
---
id: parallel-queries
title: Parallel Queries
ref: docs/framework/react/guides/parallel-queries.md
replace:
{
'If the number of queries you need to execute is changing from render to render, you cannot use manual querying since that would violate the rules of hooks. Instead, ': '',
'hook': 'function',
'React': 'Angular',
'hooks': 'functions',
'useQuery': 'injectQuery',
'useInfiniteQuery': 'injectInfiniteQuery',
'useQueries': 'injectQueries',
}
---
[//]: # 'Example'
```ts
export class AppComponent {
// The following queries will execute in parallel
usersQuery = injectQuery(() => ({ queryKey: ['users'], queryFn: fetchUsers }))
teamsQuery = injectQuery(() => ({ queryKey: ['teams'], queryFn: fetchTeams }))
projectsQuery = injectQuery(() => ({
queryKey: ['projects'],
queryFn: fetchProjects,
}))
}
```
[//]: # 'Example'
[//]: # 'Info'
[//]: # 'Info'
[//]: # 'DynamicParallelIntro'
TanStack Query provides `injectQueries`, which you can use to dynamically execute as many queries in parallel as you'd like.
[//]: # 'DynamicParallelIntro'
[//]: # 'Example2'
```ts
export class AppComponent {
users = signal>([])
// Please note injectQueries is under development and this code does not work yet
userQueries = injectQueries(() => ({
queries: users().map((user) => {
return {
queryKey: ['user', user.id],
queryFn: () => fetchUserById(user.id),
}
}),
}))
}
```
[//]: # 'Example2'
================================================
FILE: docs/framework/angular/guides/placeholder-query-data.md
================================================
---
id: placeholder-query-data
title: Placeholder Query Data
ref: docs/framework/react/guides/placeholder-query-data.md
---
[//]: # 'ExampleValue'
```ts
class TodosComponent {
result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
placeholderData: placeholderTodos,
}))
}
```
[//]: # 'ExampleValue'
[//]: # 'Memoization'
[//]: # 'Memoization'
[//]: # 'ExampleFunction'
```ts
class TodosComponent {
result = injectQuery(() => ({
queryKey: ['todos', id()],
queryFn: () => fetch(`/todos/${id}`),
placeholderData: (previousData, previousQuery) => previousData,
}))
}
```
[//]: # 'ExampleFunction'
[//]: # 'ExampleCache'
```ts
export class BlogPostComponent {
postId = input.required()
queryClient = inject(QueryClient)
result = injectQuery(() => ({
queryKey: ['blogPost', this.postId()],
queryFn: () => fetch(`/blogPosts/${this.postId()}`),
placeholderData: () => {
// Use the smaller/preview version of the blogPost from the 'blogPosts'
// query as the placeholder data for this blogPost query
return this.queryClient
.getQueryData(['blogPosts'])
?.find((d) => d.id === this.postId())
},
}))
}
```
[//]: # 'ExampleCache'
[//]: # 'Materials'
[//]: # 'Materials'
================================================
FILE: docs/framework/angular/guides/queries.md
================================================
---
id: queries
title: Queries
ref: docs/framework/react/guides/queries.md
replace:
{
'React': 'Angular',
'react-query': 'angular-query',
'promise': 'promise or observable',
'custom hooks': 'services',
'the `useQuery` hook': '`injectQuery`',
'`useQuery`': '`injectQuery`',
"TypeScript will also narrow the type of data correctly if you've checked for pending and error before accessing it.": 'TypeScript will only narrow the type when checking boolean signals such as `isPending` and `isError`.',
}
---
[//]: # 'Example'
```ts
import { injectQuery } from '@tanstack/angular-query-experimental'
export class TodosComponent {
info = injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodoList }))
}
```
[//]: # 'Example'
[//]: # 'Example2'
```ts
result = injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodoList }))
```
[//]: # 'Example2'
[//]: # 'Example3'
```angular-ts
@Component({
selector: 'todos',
template: `
@if (todos.isPending()) {
Loading...
} @else if (todos.isError()) {
Error: {{ todos.error()?.message }}
} @else {
@for (todo of todos.data(); track todo.id) {
{{ todo.title }}
} @empty {
No todos found
}
}
`,
})
export class PostsComponent {
todos = injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodoList,
}))
}
```
[//]: # 'Example3'
If booleans aren't your thing, you can always use the `status` state as well:
[//]: # 'Example4'
```angular-ts
@Component({
selector: 'todos',
template: `
@switch (todos.status()) {
@case ('pending') {
Loading...
}
@case ('error') {
Error: {{ todos.error()?.message }}
}
@default {
@for (todo of todos.data(); track todo.id) {
{{ todo.title }}
} @empty {
No todos found
}
}
}
`,
})
class TodosComponent {}
```
[//]: # 'Example4'
[//]: # 'Materials'
[//]: # 'Materials'
================================================
FILE: docs/framework/angular/guides/query-cancellation.md
================================================
---
id: query-cancellation
title: Query Cancellation
---
TanStack Query provides each query function with an [`AbortSignal` instance](https://developer.mozilla.org/docs/Web/API/AbortSignal). When a query becomes out-of-date or inactive, this `signal` will become aborted. This means that all queries are cancellable, and you can respond to the cancellation inside your query function if desired. The best part about this is that it allows you to continue to use normal async/await syntax while getting all the benefits of automatic cancellation.
## Default behavior
By default, queries that unmount or become unused before their promises are resolved are _not_ cancelled. This means that after the promise has resolved, the resulting data will be available in the cache. This is helpful if you've started receiving a query, but then unmount the component before it finishes. If you mount the component again and the query has not been garbage collected yet, data will be available.
However, if you consume the `AbortSignal`, the Promise will be cancelled (e.g. aborting the fetch) and therefore, also the Query must be cancelled. Cancelling the query will result in its state being _reverted_ to its previous state.
## Using `HttpClient`
```ts
import { HttpClient } from '@angular/common/http'
import { injectQuery } from '@tanstack/angular-query-experimental'
postQuery = injectQuery(() => ({
enabled: this.postId() > 0,
queryKey: ['post', this.postId()],
queryFn: async (context): Promise => {
const abort$ = fromEvent(context.signal, 'abort')
return lastValueFrom(this.getPost$(this.postId()).pipe(takeUntil(abort$)))
},
}))
```
## Using `fetch`
[//]: # 'Example2'
```ts
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const todosResponse = await fetch('/todos', {
// Pass the signal to one fetch
signal,
})
const todos = await todosResponse.json()
const todoDetails = todos.map(async ({ details }) => {
const response = await fetch(details, {
// Or pass it to several
signal,
})
return response.json()
})
return Promise.all(todoDetails)
},
}))
```
[//]: # 'Example2'
## Using `axios`
[//]: # 'Example3'
```ts
import axios from 'axios'
const query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: ({ signal }) =>
axios.get('/todos', {
// Pass the signal to `axios`
signal,
}),
}))
```
[//]: # 'Example3'
## Manual Cancellation
You might want to cancel a query manually. For example, if the request takes a long time to finish, you can allow the user to click a cancel button to stop the request. To do this, you just need to call `queryClient.cancelQueries({ queryKey })`, which will cancel the query and revert it back to its previous state. If you have consumed the `signal` passed to the query function, TanStack Query will additionally also cancel the Promise.
[//]: # 'Example7'
```angular-ts
@Component({
template: ``,
})
export class TodosComponent {
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const resp = await fetch('/todos', { signal })
return resp.json()
},
}))
queryClient = inject(QueryClient)
onCancel() {
this.queryClient.cancelQueries(['todos'])
}
}
```
[//]: # 'Example7'
================================================
FILE: docs/framework/angular/guides/query-functions.md
================================================
---
id: query-functions
title: Query Functions
ref: docs/framework/react/guides/query-functions.md
---
[//]: # 'Example'
```ts
injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchAllTodos }))
injectQuery(() => ({ queryKey: ['todos', todoId], queryFn: () => fetchTodoById(todoId) })
injectQuery(() => ({
queryKey: ['todos', todoId],
queryFn: async () => {
const data = await fetchTodoById(todoId)
return data
},
}))
injectQuery(() => ({
queryKey: ['todos', todoId],
queryFn: ({ queryKey }) => fetchTodoById(queryKey[1]),
}))
```
[//]: # 'Example'
[//]: # 'Example2'
```ts
todos = injectQuery(() => ({
queryKey: ['todos', todoId()],
queryFn: async () => {
if (somethingGoesWrong) {
throw new Error('Oh no!')
}
if (somethingElseGoesWrong) {
return Promise.reject(new Error('Oh no!'))
}
return data
},
}))
```
[//]: # 'Example2'
[//]: # 'Example3'
```ts
todos = injectQuery(() => ({
queryKey: ['todos', todoId()],
queryFn: async () => {
const response = await fetch('/todos/' + todoId)
if (!response.ok) {
throw new Error('Network response was not ok')
}
return response.json()
},
}))
```
[//]: # 'Example3'
[//]: # 'Example4'
```ts
result = injectQuery(() => ({
queryKey: ['todos', { status: status(), page: page() }],
queryFn: fetchTodoList,
}))
// Access the key, status and page variables in your query function!
function fetchTodoList({ queryKey }) {
const [_key, { status, page }] = queryKey
return new Promise()
}
```
[//]: # 'Example4'
================================================
FILE: docs/framework/angular/guides/query-invalidation.md
================================================
---
id: query-invalidation
title: Query Invalidation
ref: docs/framework/react/guides/query-invalidation.md
replace: { 'useQuery': 'injectQuery', 'hooks': 'functions' }
---
[//]: # 'Example2'
```ts
import { injectQuery, QueryClient } from '@tanstack/angular-query-experimental'
class QueryInvalidationExample {
queryClient = inject(QueryClient)
invalidateQueries() {
this.queryClient.invalidateQueries({ queryKey: ['todos'] })
}
// Both queries below will be invalidated
todoListQuery = injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodoList,
}))
todoListQuery = injectQuery(() => ({
queryKey: ['todos', { page: 1 }],
queryFn: fetchTodoList,
}))
}
```
[//]: # 'Example2'
You can even invalidate queries with specific variables by passing a more specific query key to the `invalidateQueries` method:
[//]: # 'Example3'
```ts
queryClient.invalidateQueries({
queryKey: ['todos', { type: 'done' }],
})
// The query below will be invalidated
todoListQuery = injectQuery(() => ({
queryKey: ['todos', { type: 'done' }],
queryFn: fetchTodoList,
}))
// However, the following query below will NOT be invalidated
todoListQuery = injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodoList,
}))
```
[//]: # 'Example3'
The `invalidateQueries` API is very flexible, so even if you want to **only** invalidate `todos` queries that don't have any more variables or subkeys, you can pass an `exact: true` option to the `invalidateQueries` method:
[//]: # 'Example4'
```ts
queryClient.invalidateQueries({
queryKey: ['todos'],
exact: true,
})
// The query below will be invalidated
todoListQuery = injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodoList,
}))
// However, the following query below will NOT be invalidated
const todoListQuery = injectQuery(() => ({
queryKey: ['todos', { type: 'done' }],
queryFn: fetchTodoList,
}))
```
[//]: # 'Example4'
If you find yourself wanting **even more** granularity, you can pass a predicate function to the `invalidateQueries` method. This function will receive each `Query` instance from the query cache and allow you to return `true` or `false` for whether you want to invalidate that query:
[//]: # 'Example5'
```ts
queryClient.invalidateQueries({
predicate: (query) =>
query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})
// The query below will be invalidated
todoListQuery = injectQuery(() => ({
queryKey: ['todos', { version: 20 }],
queryFn: fetchTodoList,
}))
// The query below will be invalidated
todoListQuery = injectQuery(() => ({
queryKey: ['todos', { version: 10 }],
queryFn: fetchTodoList,
}))
// However, the following query below will NOT be invalidated
todoListQuery = injectQuery(() => ({
queryKey: ['todos', { version: 5 }],
queryFn: fetchTodoList,
}))
```
[//]: # 'Example5'
================================================
FILE: docs/framework/angular/guides/query-keys.md
================================================
---
id: query-keys
title: Query Keys
ref: docs/framework/react/guides/query-keys.md
#todo: exhaustive-deps is at least for now React-only
---
[//]: # 'Example'
```ts
// A list of todos
injectQuery(() => ({ queryKey: ['todos'], ... }))
// Something else, whatever!
injectQuery(() => ({ queryKey: ['something', 'special'], ... }))
```
[//]: # 'Example'
[//]: # 'Example2'
```ts
// An individual todo
injectQuery(() => ({queryKey: ['todo', 5], ...}))
// An individual todo in a "preview" format
injectQuery(() => ({queryKey: ['todo', 5, {preview: true}], ...}))
// A list of todos that are "done"
injectQuery(() => ({queryKey: ['todos', {type: 'done'}], ...}))
```
[//]: # 'Example2'
[//]: # 'Example3'
```ts
injectQuery(() => ({ queryKey: ['todos', { status, page }], ... }))
injectQuery(() => ({ queryKey: ['todos', { page, status }], ...}))
injectQuery(() => ({ queryKey: ['todos', { page, status, other: undefined }], ... }))
```
[//]: # 'Example3'
[//]: # 'Example4'
```ts
injectQuery(() => ({ queryKey: ['todos', status, page], ... }))
injectQuery(() => ({ queryKey: ['todos', page, status], ...}))
injectQuery(() => ({ queryKey: ['todos', undefined, page, status], ...}))
```
[//]: # 'Example4'
[//]: # 'Example5'
```ts
todoId = signal(-1)
injectQuery(() => ({
enabled: todoId() > 0,
queryKey: ['todos', todoId()],
queryFn: () => fetchTodoById(todoId()),
}))
```
[//]: # 'Example5'
[//]: # 'Materials'
[//]: # 'Materials'
================================================
FILE: docs/framework/angular/guides/query-options.md
================================================
---
id: query-options
title: Query Options
ref: docs/framework/react/guides/query-options.md
---
[//]: # 'Example1'
```ts
import { queryOptions } from '@tanstack/angular-query-experimental'
@Injectable({
providedIn: 'root',
})
export class QueriesService {
private http = inject(HttpClient)
post(postId: number) {
return queryOptions({
queryKey: ['post', postId],
queryFn: () => {
return lastValueFrom(
this.http.get(
`https://jsonplaceholder.typicode.com/posts/${postId}`,
),
)
},
})
}
}
// usage:
postId = input.required({
transform: numberAttribute,
})
queries = inject(QueriesService)
postQuery = injectQuery(() => this.queries.post(this.postId()))
queryClient.prefetchQuery(this.queries.post(23))
queryClient.setQueryData(this.queries.post(42).queryKey, newPost)
```
[//]: # 'Example1'
[//]: # 'Example2'
```ts
// Type inference still works, so query.data will be the return type of select instead of queryFn
queries = inject(QueriesService)
query = injectQuery(() => ({
...groupOptions(1),
select: (data) => data.title,
}))
```
[//]: # 'Example2'
================================================
FILE: docs/framework/angular/guides/query-retries.md
================================================
---
id: query-retries
title: Query Retries
ref: docs/framework/react/guides/query-retries.md
replace:
{
'Provider': 'Plugin',
'useQuery': 'injectQuery',
'useMutation': 'injectMutation',
}
---
[//]: # 'Info'
[//]: # 'Info'
[//]: # 'Example'
```ts
import { injectQuery } from '@tanstack/angular-query-experimental'
// Make a specific query retry a certain number of times
const result = injectQuery(() => ({
queryKey: ['todos', 1],
queryFn: fetchTodoListPage,
retry: 10, // Will retry failed requests 10 times before displaying an error
}))
```
[//]: # 'Example'
[//]: # 'Example2'
```ts
// Configure for all queries
import {
QueryCache,
QueryClient,
QueryClientProvider,
} from '@tanstack/angular-query-experimental'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
},
},
})
bootstrapApplication(AppComponent, {
providers: [provideTanStackQuery(queryClient)],
})
```
[//]: # 'Example2'
Though it is not recommended, you can obviously override the `retryDelay` function/integer in both the Provider and individual query options. If set to an integer instead of a function the delay will always be the same amount of time:
[//]: # 'Example3'
```ts
const result = injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodoList,
retryDelay: 1000, // Will always wait 1000ms to retry, regardless of how many retries
}))
```
[//]: # 'Example3'
================================================
FILE: docs/framework/angular/guides/scroll-restoration.md
================================================
---
id: scroll-restoration
title: Scroll Restoration
ref: docs/framework/react/guides/scroll-restoration.md
---
================================================
FILE: docs/framework/angular/guides/testing.md
================================================
---
id: testing
title: Testing
---
Most Angular tests using TanStack Query will involve services or components that call `injectQuery`/`injectMutation`.
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 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`.
## 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:
```ts
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false, // ✅ faster failure tests
},
},
})
TestBed.configureTestingModule({
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 you share helpers, remember to call `queryClient.clear()` (or build a new instance) in `afterEach` so data from one test never bleeds into another.
## First query test
Query tests typically run inside `TestBed.runInInjectionContext`, then wait for stability:
```ts
const appRef = TestBed.inject(ApplicationRef)
const query = TestBed.runInInjectionContext(() =>
injectQuery(() => ({
queryKey: ['greeting'],
queryFn: () => 'Hello',
})),
)
TestBed.tick() // Trigger effect
// Application is stable when queries are idle
await appRef.whenStable()
expect(query.status()).toBe('success')
expect(query.data()).toBe('Hello')
```
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)
await Promise.resolve()
await appRef.whenStable()
```
## Testing components
For components, bootstrap them through `TestBed.createComponent`, then await `fixture.whenStable()`:
```ts
const fixture = TestBed.createComponent(ExampleComponent)
await fixture.whenStable()
expect(fixture.componentInstance.query.data()).toEqual({ value: 42 })
```
## Handling retries
Retries slow failing tests because the default backoff runs three times. Set `retry: false` (or a specific number) through `defaultOptions` or per query to keep tests fast. If a query intentionally retries, assert on the final state rather than intermediate counts.
## HttpClient & network stubs
Angular's `HttpClientTestingModule` plays nicely with PendingTasks. Register it alongside the Query provider and flush responses through `HttpTestingController`:
```ts
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [provideTanStackQuery(queryClient)],
})
const httpCtrl = TestBed.inject(HttpTestingController)
const query = TestBed.runInInjectionContext(() =>
injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => lastValueFrom(TestBed.inject(HttpClient).get('/api/todos')),
})),
)
const fixturePromise = TestBed.inject(ApplicationRef).whenStable()
httpCtrl.expectOne('/api/todos').flush([{ id: 1 }])
await fixturePromise
expect(query.data()).toEqual([{ id: 1 }])
httpCtrl.verify()
```
## Infinite queries & pagination
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
const infinite = TestBed.runInInjectionContext(() =>
injectInfiniteQuery(() => ({
queryKey: ['pages'],
queryFn: ({ pageParam = 1 }) => fetchPage(pageParam),
getNextPageParam: (last, all) => all.length + 1,
})),
)
await appRef.whenStable()
expect(infinite.data().pages).toHaveLength(1)
await infinite.fetchNextPage()
await vi.advanceTimersByTimeAsync(0)
await appRef.whenStable()
expect(infinite.data().pages).toHaveLength(2)
```
## Mutations and optimistic updates
```ts
const mutation = TestBed.runInInjectionContext(() =>
injectMutation(() => ({
mutationFn: async (input: string) => input.toUpperCase(),
})),
)
mutation.mutate('test')
// Trigger effect
TestBed.tick()
await appRef.whenStable()
expect(mutation.isSuccess()).toBe(true)
expect(mutation.data()).toBe('TEST')
```
## 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 `HttpClientTestingModule` or your preferred mock to assert network calls
- Await `whenStable()` after every `refetch`, `fetchNextPage`, or mutation
- Prefer `TestBed.runInInjectionContext` for service tests and `fixture.whenStable()` for component tests
================================================
FILE: docs/framework/angular/guides/window-focus-refetching.md
================================================
---
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' }
---
[//]: # 'Example'
```ts
export const appConfig: ApplicationConfig = {
providers: [
provideTanStackQuery(
new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false, // default: true
},
},
}),
),
],
}
```
[//]: # 'Example'
[//]: # 'Example2'
```ts
injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodos,
refetchOnWindowFocus: false,
}))
```
[//]: # 'Example2'
[//]: # 'ReactNative'
[//]: # 'ReactNative'
================================================
FILE: docs/framework/angular/installation.md
================================================
---
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.
### NPM
_Angular Query is compatible with Angular v16 and higher_
```bash
npm i @tanstack/angular-query-experimental
```
or
```bash
pnpm add @tanstack/angular-query-experimental
```
or
```bash
yarn add @tanstack/angular-query-experimental
```
or
```bash
bun add @tanstack/angular-query-experimental
```
> Wanna give it a spin before you download? Try out the [simple](./examples/simple) or [basic](./examples/basic) examples!
================================================
FILE: docs/framework/angular/overview.md
================================================
---
id: overview
title: Overview
---
> 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-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.
## Supported Angular Versions
TanStack Query is compatible with Angular v16 and higher.
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.
## Motivation
Most core web frameworks **do not** come with an opinionated way of fetching or updating data in a holistic way. Because of this developers end up building either meta-frameworks which encapsulate strict opinions about data-fetching, or they invent their own ways of fetching data. This usually means cobbling together component-based state and side-effects, or using more general purpose state management libraries to store and provide asynchronous data throughout their apps.
While most traditional state management libraries are great for working with client state, they are **not so great at working with async or server state**. This is because **server state is totally different**. For starters, server state:
- Is persisted remotely in a location you may not control or own
- Requires asynchronous APIs for fetching and updating
- Implies shared ownership and can be changed by other people without your knowledge
- Can potentially become "out of date" in your applications if you're not careful
Once you grasp the nature of server state in your application, **even more challenges will arise** as you go, for example:
- Caching... (possibly the hardest thing to do in programming)
- Deduping multiple requests for the same data into a single request
- Updating "out of date" data in the background
- Knowing when data is "out of date"
- Reflecting updates to data as quickly as possible
- Performance optimizations like pagination and lazy loading data
- Managing memory and garbage collection of server state
- Memoizing query results with structural sharing
If you're not overwhelmed by that list, then that must mean that you've probably solved all of your server state problems already and deserve an award. However, if you are like a vast majority of people, you either have yet to tackle all or most of these challenges and we're only scratching the surface!
TanStack Query is hands down one of the _best_ libraries for managing server state. It works amazingly well **out-of-the-box, with zero-config, and can be customized** to your liking as your application grows.
TanStack Query allows you to defeat and overcome the tricky challenges and hurdles of _server state_ and control your app data before it starts to control you.
On a more technical note, TanStack Query will likely:
- Help you remove **many** lines of complicated and misunderstood code from your application and replace with just a handful of lines of Angular Query logic.
- Make your application more maintainable and easier to build new features without worrying about wiring up new server state data sources
- Have a direct impact on your end-users by making your application feel faster and more responsive than ever before.
- Potentially help you save on bandwidth and increase memory performance
[//]: # 'Example'
## Enough talk, show me some code already!
In the example below, you can see TanStack Query in its most basic and simple form being used to fetch the GitHub stats for the TanStack Query GitHub project itself:
[Open in StackBlitz](https://stackblitz.com/github/TanStack/query/tree/main/examples/angular/simple)
```angular-ts
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { CommonModule } from '@angular/common'
import { injectQuery } from '@tanstack/angular-query-experimental'
import { lastValueFrom } from 'rxjs'
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'simple-example',
template: `
@if (query.isPending()) {
Loading...
}
@if (query.error()) {
An error has occurred: {{ query.error().message }}
}
@if (query.data(); as data) {
{{ data.name }}
{{ data.description }}
👀 {{ data.subscribers_count }}✨ {{ data.stargazers_count }}🍴 {{ data.forks_count }}
}
`,
})
export class SimpleExampleComponent {
http = inject(HttpClient)
query = injectQuery(() => ({
queryKey: ['repoData'],
queryFn: () =>
lastValueFrom(
this.http.get('https://api.github.com/repos/tanstack/query'),
),
}))
}
interface Response {
name: string
description: string
subscribers_count: number
stargazers_count: number
forks_count: number
}
```
## You talked me into it, so what now?
- Learn TanStack Query at your own pace with our amazingly thorough [Walkthrough Guide](./installation.md) and [API Reference](./reference/functions/injectQuery.md)
================================================
FILE: docs/framework/angular/quick-start.md
================================================
---
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
```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
```ts
import { provideHttpClient } from '@angular/common/http'
import {
provideTanStackQuery,
QueryClient,
} from '@tanstack/angular-query-experimental'
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [provideTanStackQuery(new QueryClient())],
bootstrap: [AppComponent],
})
export class AppModule {}
```
### Component with query and mutation
```angular-ts
import { Component, Injectable, inject } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { lastValueFrom } from 'rxjs'
import {
injectMutation,
injectQuery,
QueryClient,
} from '@tanstack/angular-query-experimental'
@Component({
template: `
@for (todo of query.data(); track todo.title) {
{{ todo.title }}
}
`,
})
export class TodosComponent {
todoService = inject(TodoService)
queryClient = inject(QueryClient)
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: () => this.todoService.getTodos(),
}))
mutation = injectMutation(() => ({
mutationFn: (todo: Todo) => this.todoService.addTodo(todo),
onSuccess: () => {
this.queryClient.invalidateQueries({ queryKey: ['todos'] })
},
}))
onAddTodo() {
this.mutation.mutate({
id: Date.now().toString(),
title: 'Do Laundry',
})
}
}
@Injectable({ providedIn: 'root' })
export class TodoService {
private http = inject(HttpClient)
getTodos(): Promise {
return lastValueFrom(
this.http.get('https://jsonplaceholder.typicode.com/todos'),
)
}
addTodo(todo: Todo): Promise {
return lastValueFrom(
this.http.post('https://jsonplaceholder.typicode.com/todos', todo),
)
}
}
interface Todo {
id: string
title: string
}
```
[//]: # 'Example'
================================================
FILE: docs/framework/angular/reference/functions/infiniteQueryOptions.md
================================================
---
id: infiniteQueryOptions
title: infiniteQueryOptions
---
# Function: infiniteQueryOptions()
Allows to share and re-use infinite query options in a type-safe way.
The `queryKey` will be tagged with the type from `queryFn`.
## Param
The infinite query options to tag with the type from `queryFn`.
## Call Signature
```ts
function infiniteQueryOptions(options): CreateInfiniteQueryOptions & object & object;
```
Defined in: [infinite-query-options.ts:88](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L88)
Allows to share and re-use infinite query options in a type-safe way.
The `queryKey` will be tagged with the type from `queryFn`.
### Type Parameters
#### TQueryFnData
`TQueryFnData`
#### TError
`TError` = `Error`
#### TData
`TData` = `InfiniteData`\<`TQueryFnData`, `unknown`\>
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
#### TPageParam
`TPageParam` = `unknown`
### Parameters
#### options
[`DefinedInitialDataInfiniteOptions`](../type-aliases/DefinedInitialDataInfiniteOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
The infinite query options to tag with the type from `queryFn`.
### Returns
[`CreateInfiniteQueryOptions`](../interfaces/CreateInfiniteQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\> & `object` & `object`
The tagged infinite query options.
## Call Signature
```ts
function infiniteQueryOptions(options): OmitKeyof, "queryFn"> & object & object;
```
Defined in: [infinite-query-options.ts:119](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L119)
Allows to share and re-use infinite query options in a type-safe way.
The `queryKey` will be tagged with the type from `queryFn`.
### Type Parameters
#### TQueryFnData
`TQueryFnData`
#### TError
`TError` = `Error`
#### TData
`TData` = `InfiniteData`\<`TQueryFnData`, `unknown`\>
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
#### TPageParam
`TPageParam` = `unknown`
### Parameters
#### options
[`UnusedSkipTokenInfiniteOptions`](../type-aliases/UnusedSkipTokenInfiniteOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
The infinite query options to tag with the type from `queryFn`.
### Returns
`OmitKeyof`\<[`CreateInfiniteQueryOptions`](../interfaces/CreateInfiniteQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>, `"queryFn"`\> & `object` & `object`
The tagged infinite query options.
## Call Signature
```ts
function infiniteQueryOptions(options): CreateInfiniteQueryOptions & object & object;
```
Defined in: [infinite-query-options.ts:150](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L150)
Allows to share and re-use infinite query options in a type-safe way.
The `queryKey` will be tagged with the type from `queryFn`.
### Type Parameters
#### TQueryFnData
`TQueryFnData`
#### TError
`TError` = `Error`
#### TData
`TData` = `InfiniteData`\<`TQueryFnData`, `unknown`\>
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
#### TPageParam
`TPageParam` = `unknown`
### Parameters
#### options
[`UndefinedInitialDataInfiniteOptions`](../type-aliases/UndefinedInitialDataInfiniteOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
The infinite query options to tag with the type from `queryFn`.
### Returns
[`CreateInfiniteQueryOptions`](../interfaces/CreateInfiniteQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\> & `object` & `object`
The tagged infinite query options.
================================================
FILE: docs/framework/angular/reference/functions/injectInfiniteQuery.md
================================================
---
id: injectInfiniteQuery
title: injectInfiniteQuery
---
# Function: injectInfiniteQuery()
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"
## Param
A function that returns infinite query options.
## Param
Additional configuration.
## Call Signature
```ts
function injectInfiniteQuery(injectInfiniteQueryFn, options?): DefinedCreateInfiniteQueryResult;
```
Defined in: [inject-infinite-query.ts:41](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L41)
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"
### Type Parameters
#### TQueryFnData
`TQueryFnData`
#### TError
`TError` = `Error`
#### TData
`TData` = `InfiniteData`\<`TQueryFnData`, `unknown`\>
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
#### TPageParam
`TPageParam` = `unknown`
### Parameters
#### injectInfiniteQueryFn
() => [`DefinedInitialDataInfiniteOptions`](../type-aliases/DefinedInitialDataInfiniteOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
A function that returns infinite query options.
#### options?
[`InjectInfiniteQueryOptions`](../interfaces/InjectInfiniteQueryOptions.md)
Additional configuration.
### Returns
[`DefinedCreateInfiniteQueryResult`](../type-aliases/DefinedCreateInfiniteQueryResult.md)\<`TData`, `TError`\>
The infinite query result.
## Call Signature
```ts
function injectInfiniteQuery(injectInfiniteQueryFn, options?): CreateInfiniteQueryResult;
```
Defined in: [inject-infinite-query.ts:65](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L65)
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"
### Type Parameters
#### TQueryFnData
`TQueryFnData`
#### TError
`TError` = `Error`
#### TData
`TData` = `InfiniteData`\<`TQueryFnData`, `unknown`\>
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
#### TPageParam
`TPageParam` = `unknown`
### Parameters
#### injectInfiniteQueryFn
() => [`UndefinedInitialDataInfiniteOptions`](../type-aliases/UndefinedInitialDataInfiniteOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
A function that returns infinite query options.
#### options?
[`InjectInfiniteQueryOptions`](../interfaces/InjectInfiniteQueryOptions.md)
Additional configuration.
### Returns
[`CreateInfiniteQueryResult`](../type-aliases/CreateInfiniteQueryResult.md)\<`TData`, `TError`\>
The infinite query result.
## Call Signature
```ts
function injectInfiniteQuery(injectInfiniteQueryFn, options?): CreateInfiniteQueryResult;
```
Defined in: [inject-infinite-query.ts:89](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L89)
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"
### Type Parameters
#### TQueryFnData
`TQueryFnData`
#### TError
`TError` = `Error`
#### TData
`TData` = `InfiniteData`\<`TQueryFnData`, `unknown`\>
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
#### TPageParam
`TPageParam` = `unknown`
### Parameters
#### injectInfiniteQueryFn
() => [`CreateInfiniteQueryOptions`](../interfaces/CreateInfiniteQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
A function that returns infinite query options.
#### options?
[`InjectInfiniteQueryOptions`](../interfaces/InjectInfiniteQueryOptions.md)
Additional configuration.
### Returns
[`CreateInfiniteQueryResult`](../type-aliases/CreateInfiniteQueryResult.md)\<`TData`, `TError`\>
The infinite query result.
================================================
FILE: docs/framework/angular/reference/functions/injectIsFetching.md
================================================
---
id: injectIsFetching
title: injectIsFetching
---
# Function: injectIsFetching()
```ts
function injectIsFetching(filters?, options?): Signal;
```
Defined in: [inject-is-fetching.ts:31](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-fetching.ts#L31)
Injects a signal that tracks the number of queries that your application is loading or
fetching in the background.
Can be used for app-wide loading indicators
## Parameters
### filters?
`QueryFilters`\
The filters to apply to the query.
### options?
[`InjectIsFetchingOptions`](../interfaces/InjectIsFetchingOptions.md)
Additional configuration
## Returns
`Signal`\<`number`\>
signal with number of loading or fetching queries.
================================================
FILE: docs/framework/angular/reference/functions/injectIsMutating.md
================================================
---
id: injectIsMutating
title: injectIsMutating
---
# Function: injectIsMutating()
```ts
function injectIsMutating(filters?, options?): Signal;
```
Defined in: [inject-is-mutating.ts:30](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-mutating.ts#L30)
Injects a signal that tracks the number of mutations that your application is fetching.
Can be used for app-wide loading indicators
## Parameters
### filters?
`MutationFilters`\<`unknown`, `Error`, `unknown`, `unknown`\>
The filters to apply to the query.
### options?
[`InjectIsMutatingOptions`](../interfaces/InjectIsMutatingOptions.md)
Additional configuration
## Returns
`Signal`\<`number`\>
A read-only signal with the number of fetching mutations.
================================================
FILE: docs/framework/angular/reference/functions/injectIsRestoring.md
================================================
---
id: injectIsRestoring
title: injectIsRestoring
---
# Function: injectIsRestoring()
```ts
function injectIsRestoring(options?): Signal;
```
Defined in: [inject-is-restoring.ts:32](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-restoring.ts#L32)
Injects a signal that tracks whether a restore is currently in progress. [injectQuery](injectQuery.md) and friends also check this internally to avoid race conditions between the restore and initializing queries.
## Parameters
### options?
`InjectIsRestoringOptions`
Options for injectIsRestoring.
## Returns
`Signal`\<`boolean`\>
readonly signal with boolean that indicates whether a restore is in progress.
================================================
FILE: docs/framework/angular/reference/functions/injectMutation.md
================================================
---
id: injectMutation
title: injectMutation
---
# Function: injectMutation()
```ts
function injectMutation(injectMutationFn, options?): CreateMutationResult;
```
Defined in: [inject-mutation.ts:45](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L45)
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
### TData
`TData` = `unknown`
### TError
`TError` = `Error`
### TVariables
`TVariables` = `void`
### TOnMutateResult
`TOnMutateResult` = `unknown`
## Parameters
### injectMutationFn
() => [`CreateMutationOptions`](../interfaces/CreateMutationOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
A function that returns mutation options.
### options?
[`InjectMutationOptions`](../interfaces/InjectMutationOptions.md)
Additional configuration
## Returns
[`CreateMutationResult`](../type-aliases/CreateMutationResult.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
The mutation.
================================================
FILE: docs/framework/angular/reference/functions/injectMutationState.md
================================================
---
id: injectMutationState
title: injectMutationState
---
# Function: injectMutationState()
```ts
function injectMutationState(injectMutationStateFn, options?): Signal;
```
Defined in: [inject-mutation-state.ts:60](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation-state.ts#L60)
Injects a signal that tracks the state of all mutations.
## Type Parameters
### TResult
`TResult` = `MutationState`\<`unknown`, `Error`, `unknown`, `unknown`\>
## Parameters
### injectMutationStateFn
() => `MutationStateOptions`\<`TResult`\>
A function that returns mutation state options.
### options?
[`InjectMutationStateOptions`](../interfaces/InjectMutationStateOptions.md)
The Angular injector to use.
## Returns
`Signal`\<`TResult`[]\>
The signal that tracks the state of all mutations.
================================================
FILE: docs/framework/angular/reference/functions/injectQuery.md
================================================
---
id: injectQuery
title: injectQuery
---
# Function: injectQuery()
Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
**Basic example**
```ts
class ServiceOrComponent {
query = injectQuery(() => ({
queryKey: ['repoData'],
queryFn: () =>
this.#http.get('https://api.github.com/repos/tanstack/query'),
}))
}
```
Similar to `computed` from Angular, the function passed to `injectQuery` will be run in the reactive context.
In the example below, the query will be automatically enabled and executed when the filter signal changes
to a truthy value. When the filter signal changes back to a falsy value, the query will be disabled.
**Reactive example**
```ts
class ServiceOrComponent {
filter = signal('')
todosQuery = injectQuery(() => ({
queryKey: ['todos', this.filter()],
queryFn: () => fetchTodos(this.filter()),
// Signals can be combined with expressions
enabled: !!this.filter(),
}))
}
```
## Param
A function that returns query options.
## Param
Additional configuration
## See
https://tanstack.com/query/latest/docs/framework/angular/guides/queries
## Call Signature
```ts
function injectQuery(injectQueryFn, options?): DefinedCreateQueryResult;
```
Defined in: [inject-query.ts:65](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L65)
Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
**Basic example**
```ts
class ServiceOrComponent {
query = injectQuery(() => ({
queryKey: ['repoData'],
queryFn: () =>
this.#http.get('https://api.github.com/repos/tanstack/query'),
}))
}
```
Similar to `computed` from Angular, the function passed to `injectQuery` will be run in the reactive context.
In the example below, the query will be automatically enabled and executed when the filter signal changes
to a truthy value. When the filter signal changes back to a falsy value, the query will be disabled.
**Reactive example**
```ts
class ServiceOrComponent {
filter = signal('')
todosQuery = injectQuery(() => ({
queryKey: ['todos', this.filter()],
queryFn: () => fetchTodos(this.filter()),
// Signals can be combined with expressions
enabled: !!this.filter(),
}))
}
```
### Type Parameters
#### TQueryFnData
`TQueryFnData` = `unknown`
#### TError
`TError` = `Error`
#### TData
`TData` = `TQueryFnData`
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
### Parameters
#### injectQueryFn
() => [`DefinedInitialDataOptions`](../type-aliases/DefinedInitialDataOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
A function that returns query options.
#### options?
[`InjectQueryOptions`](../interfaces/InjectQueryOptions.md)
Additional configuration
### Returns
[`DefinedCreateQueryResult`](../type-aliases/DefinedCreateQueryResult.md)\<`TData`, `TError`\>
The query result.
### See
https://tanstack.com/query/latest/docs/framework/angular/guides/queries
## Call Signature
```ts
function injectQuery(injectQueryFn, options?): CreateQueryResult;
```
Defined in: [inject-query.ts:116](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L116)
Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
**Basic example**
```ts
class ServiceOrComponent {
query = injectQuery(() => ({
queryKey: ['repoData'],
queryFn: () =>
this.#http.get('https://api.github.com/repos/tanstack/query'),
}))
}
```
Similar to `computed` from Angular, the function passed to `injectQuery` will be run in the reactive context.
In the example below, the query will be automatically enabled and executed when the filter signal changes
to a truthy value. When the filter signal changes back to a falsy value, the query will be disabled.
**Reactive example**
```ts
class ServiceOrComponent {
filter = signal('')
todosQuery = injectQuery(() => ({
queryKey: ['todos', this.filter()],
queryFn: () => fetchTodos(this.filter()),
// Signals can be combined with expressions
enabled: !!this.filter(),
}))
}
```
### Type Parameters
#### TQueryFnData
`TQueryFnData` = `unknown`
#### TError
`TError` = `Error`
#### TData
`TData` = `TQueryFnData`
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
### Parameters
#### injectQueryFn
() => [`UndefinedInitialDataOptions`](../type-aliases/UndefinedInitialDataOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
A function that returns query options.
#### options?
[`InjectQueryOptions`](../interfaces/InjectQueryOptions.md)
Additional configuration
### Returns
[`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`TData`, `TError`\>
The query result.
### See
https://tanstack.com/query/latest/docs/framework/angular/guides/queries
## Call Signature
```ts
function injectQuery(injectQueryFn, options?): CreateQueryResult;
```
Defined in: [inject-query.ts:167](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L167)
Injects a query: a declarative dependency on an asynchronous source of data that is tied to a unique key.
**Basic example**
```ts
class ServiceOrComponent {
query = injectQuery(() => ({
queryKey: ['repoData'],
queryFn: () =>
this.#http.get('https://api.github.com/repos/tanstack/query'),
}))
}
```
Similar to `computed` from Angular, the function passed to `injectQuery` will be run in the reactive context.
In the example below, the query will be automatically enabled and executed when the filter signal changes
to a truthy value. When the filter signal changes back to a falsy value, the query will be disabled.
**Reactive example**
```ts
class ServiceOrComponent {
filter = signal('')
todosQuery = injectQuery(() => ({
queryKey: ['todos', this.filter()],
queryFn: () => fetchTodos(this.filter()),
// Signals can be combined with expressions
enabled: !!this.filter(),
}))
}
```
### Type Parameters
#### TQueryFnData
`TQueryFnData` = `unknown`
#### TError
`TError` = `Error`
#### TData
`TData` = `TQueryFnData`
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
### Parameters
#### injectQueryFn
() => [`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
A function that returns query options.
#### options?
[`InjectQueryOptions`](../interfaces/InjectQueryOptions.md)
Additional configuration
### Returns
[`CreateQueryResult`](../type-aliases/CreateQueryResult.md)\<`TData`, `TError`\>
The query result.
### See
https://tanstack.com/query/latest/docs/framework/angular/guides/queries
================================================
FILE: docs/framework/angular/reference/functions/injectQueryClient.md
================================================
---
id: injectQueryClient
title: injectQueryClient
---
# ~~Function: injectQueryClient()~~
```ts
function injectQueryClient(injectOptions): QueryClient;
```
Defined in: [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`
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();
```
================================================
FILE: docs/framework/angular/reference/functions/mutationOptions.md
================================================
---
id: mutationOptions
title: mutationOptions
---
# Function: mutationOptions()
Allows to share and re-use mutation options in a type-safe way.
**Example**
```ts
export class QueriesService {
private http = inject(HttpClient)
private queryClient = inject(QueryClient)
updatePost(id: number) {
return mutationOptions({
mutationFn: (post: Post) => Promise.resolve(post),
mutationKey: ["updatePost", id],
onSuccess: (newPost) => {
// ^? newPost: Post
this.queryClient.setQueryData(["posts", id], newPost)
},
});
}
}
class ComponentOrService {
queries = inject(QueriesService)
id = signal(0)
mutation = injectMutation(() => this.queries.updatePost(this.id()))
save() {
this.mutation.mutate({ title: 'New Title' })
}
}
```
## Param
The mutation options.
## Call Signature
```ts
function mutationOptions(options): WithRequired, "mutationKey">;
```
Defined in: [mutation-options.ts:39](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/mutation-options.ts#L39)
Allows to share and re-use mutation options in a type-safe way.
**Example**
```ts
export class QueriesService {
private http = inject(HttpClient)
private queryClient = inject(QueryClient)
updatePost(id: number) {
return mutationOptions({
mutationFn: (post: Post) => Promise.resolve(post),
mutationKey: ["updatePost", id],
onSuccess: (newPost) => {
// ^? newPost: Post
this.queryClient.setQueryData(["posts", id], newPost)
},
});
}
}
class ComponentOrService {
queries = inject(QueriesService)
id = signal(0)
mutation = injectMutation(() => this.queries.updatePost(this.id()))
save() {
this.mutation.mutate({ title: 'New Title' })
}
}
```
### Type Parameters
#### TData
`TData` = `unknown`
#### TError
`TError` = `Error`
#### TVariables
`TVariables` = `void`
#### TOnMutateResult
`TOnMutateResult` = `unknown`
### Parameters
#### options
`WithRequired`\<[`CreateMutationOptions`](../interfaces/CreateMutationOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>, `"mutationKey"`\>
The mutation options.
### Returns
`WithRequired`\<[`CreateMutationOptions`](../interfaces/CreateMutationOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>, `"mutationKey"`\>
Mutation options.
## Call Signature
```ts
function mutationOptions(options): Omit, "mutationKey">;
```
Defined in: [mutation-options.ts:53](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/mutation-options.ts#L53)
Allows to share and re-use mutation options in a type-safe way.
**Example**
```ts
export class QueriesService {
private http = inject(HttpClient)
private queryClient = inject(QueryClient)
updatePost(id: number) {
return mutationOptions({
mutationFn: (post: Post) => Promise.resolve(post),
mutationKey: ["updatePost", id],
onSuccess: (newPost) => {
// ^? newPost: Post
this.queryClient.setQueryData(["posts", id], newPost)
},
});
}
}
class ComponentOrService {
queries = inject(QueriesService)
id = signal(0)
mutation = injectMutation(() => this.queries.updatePost(this.id()))
save() {
this.mutation.mutate({ title: 'New Title' })
}
}
```
### Type Parameters
#### TData
`TData` = `unknown`
#### TError
`TError` = `Error`
#### TVariables
`TVariables` = `void`
#### TOnMutateResult
`TOnMutateResult` = `unknown`
### Parameters
#### options
`Omit`\<[`CreateMutationOptions`](../interfaces/CreateMutationOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>, `"mutationKey"`\>
The mutation options.
### Returns
`Omit`\<[`CreateMutationOptions`](../interfaces/CreateMutationOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>, `"mutationKey"`\>
Mutation options.
================================================
FILE: docs/framework/angular/reference/functions/provideAngularQuery.md
================================================
---
id: provideAngularQuery
title: provideAngularQuery
---
# ~~Function: provideAngularQuery()~~
```ts
function provideAngularQuery(queryClient): Provider[];
```
Defined in: [providers.ts:124](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L124)
Sets up providers necessary to enable TanStack Query functionality for Angular applications.
Allows to configure a `QueryClient`.
## Parameters
### queryClient
`QueryClient`
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.
================================================
FILE: docs/framework/angular/reference/functions/provideIsRestoring.md
================================================
---
id: provideIsRestoring
title: provideIsRestoring
---
# Function: provideIsRestoring()
```ts
function provideIsRestoring(isRestoring): Provider;
```
Defined in: [inject-is-restoring.ts:43](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-restoring.ts#L43)
Used by TanStack Query Angular persist client plugin to provide the signal that tracks the restore state
## Parameters
### isRestoring
`Signal`\<`boolean`\>
a readonly signal that returns a boolean
## Returns
`Provider`
Provider for the `isRestoring` signal
================================================
FILE: docs/framework/angular/reference/functions/provideQueryClient.md
================================================
---
id: provideQueryClient
title: provideQueryClient
---
# Function: provideQueryClient()
```ts
function provideQueryClient(queryClient): Provider;
```
Defined in: [providers.ts:14](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L14)
Usually [provideTanStackQuery](provideTanStackQuery.md) is used once to set up TanStack Query and the
[https://tanstack.com/query/latest/docs/reference/QueryClient\|QueryClient](https://tanstack.com/query/latest/docs/reference/QueryClient|QueryClient)
for the entire application. Internally it calls `provideQueryClient`.
You can use `provideQueryClient` to provide a different `QueryClient` instance for a part
of the application or for unit testing purposes.
## Parameters
### queryClient
A `QueryClient` instance, or an `InjectionToken` which provides a `QueryClient`.
`QueryClient` | `InjectionToken`\<`QueryClient`\>
## Returns
`Provider`
a provider object that can be used to provide the `QueryClient` instance.
================================================
FILE: docs/framework/angular/reference/functions/provideTanStackQuery.md
================================================
---
id: provideTanStackQuery
title: provideTanStackQuery
---
# Function: provideTanStackQuery()
```ts
function provideTanStackQuery(queryClient, ...features): Provider[];
```
Defined in: [providers.ts:105](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L105)
Sets up providers necessary to enable TanStack Query functionality for Angular applications.
Allows to configure a `QueryClient` and optional features such as developer tools.
**Example - standalone**
```ts
import {
provideTanStackQuery,
QueryClient,
} from '@tanstack/angular-query-experimental'
bootstrapApplication(AppComponent, {
providers: [provideTanStackQuery(new QueryClient())],
})
```
**Example - NgModule-based**
```ts
import {
provideTanStackQuery,
QueryClient,
} from '@tanstack/angular-query-experimental'
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [provideTanStackQuery(new QueryClient())],
bootstrap: [AppComponent],
})
export class AppModule {}
```
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
import {
provideTanStackQuery,
withDevtools
QueryClient,
} from '@tanstack/angular-query-experimental'
bootstrapApplication(AppComponent,
{
providers: [
provideTanStackQuery(new QueryClient(), withDevtools())
]
}
)
```
**Example: using an InjectionToken**
```ts
export const MY_QUERY_CLIENT = new InjectionToken('', {
factory: () => new QueryClient(),
})
// In a lazy loaded route or lazy loaded component's providers array:
providers: [provideTanStackQuery(MY_QUERY_CLIENT)]
```
Using an InjectionToken for the QueryClient is an advanced optimization which allows TanStack Query to be absent from the main application bundle.
This can be beneficial if you want to include TanStack Query on lazy loaded routes only while still sharing a `QueryClient`.
Note that this is a small optimization and for most applications it's preferable to provide the `QueryClient` in the main application config.
## Parameters
### queryClient
A `QueryClient` instance, or an `InjectionToken` which provides a `QueryClient`.
`QueryClient` | `InjectionToken`\<`QueryClient`\>
### features
...[`QueryFeatures`](../type-aliases/QueryFeatures.md)[]
Optional features to configure additional Query functionality.
## Returns
`Provider`[]
A set of providers to set up TanStack Query.
## See
- https://tanstack.com/query/v5/docs/framework/angular/quick-start
- withDevtools
================================================
FILE: docs/framework/angular/reference/functions/queryFeature.md
================================================
---
id: queryFeature
title: queryFeature
---
# Function: queryFeature()
```ts
function queryFeature(kind, providers): QueryFeature;
```
Defined in: [providers.ts:146](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L146)
Helper function to create an object that represents a Query feature.
## Type Parameters
### TFeatureKind
`TFeatureKind` *extends* `"Devtools"` \| `"PersistQueryClient"`
## Parameters
### kind
`TFeatureKind`
### providers
`Provider`[]
## Returns
[`QueryFeature`](../interfaces/QueryFeature.md)\<`TFeatureKind`\>
A Query feature.
================================================
FILE: docs/framework/angular/reference/functions/queryOptions.md
================================================
---
id: queryOptions
title: queryOptions
---
# Function: queryOptions()
Allows to share and re-use query options in a type-safe way.
The `queryKey` will be tagged with the type from `queryFn`.
**Example**
```ts
const { queryKey } = queryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// ^? Promise
})
const queryClient = new QueryClient()
const data = queryClient.getQueryData(queryKey)
// ^? number | undefined
```
## Param
The query options to tag with the type from `queryFn`.
## Call Signature
```ts
function queryOptions(options): Omit, "queryFn"> & object & object;
```
Defined in: [query-options.ts:76](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L76)
Allows to share and re-use query options in a type-safe way.
The `queryKey` will be tagged with the type from `queryFn`.
**Example**
```ts
const { queryKey } = queryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// ^? Promise
})
const queryClient = new QueryClient()
const data = queryClient.getQueryData(queryKey)
// ^? number | undefined
```
### Type Parameters
#### TQueryFnData
`TQueryFnData` = `unknown`
#### TError
`TError` = `Error`
#### TData
`TData` = `TQueryFnData`
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
### Parameters
#### options
[`DefinedInitialDataOptions`](../type-aliases/DefinedInitialDataOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
The query options to tag with the type from `queryFn`.
### Returns
`Omit`\<[`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>, `"queryFn"`\> & `object` & `object`
The tagged query options.
## Call Signature
```ts
function queryOptions(options): OmitKeyof, "queryFn"> & object & object;
```
Defined in: [query-options.ts:108](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L108)
Allows to share and re-use query options in a type-safe way.
The `queryKey` will be tagged with the type from `queryFn`.
**Example**
```ts
const { queryKey } = queryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// ^? Promise
})
const queryClient = new QueryClient()
const data = queryClient.getQueryData(queryKey)
// ^? number | undefined
```
### Type Parameters
#### TQueryFnData
`TQueryFnData` = `unknown`
#### TError
`TError` = `Error`
#### TData
`TData` = `TQueryFnData`
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
### Parameters
#### options
[`UnusedSkipTokenOptions`](../type-aliases/UnusedSkipTokenOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
The query options to tag with the type from `queryFn`.
### Returns
`OmitKeyof`\<[`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>, `"queryFn"`\> & `object` & `object`
The tagged query options.
## Call Signature
```ts
function queryOptions(options): CreateQueryOptions & object & object;
```
Defined in: [query-options.ts:140](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L140)
Allows to share and re-use query options in a type-safe way.
The `queryKey` will be tagged with the type from `queryFn`.
**Example**
```ts
const { queryKey } = queryOptions({
queryKey: ['key'],
queryFn: () => Promise.resolve(5),
// ^? Promise
})
const queryClient = new QueryClient()
const data = queryClient.getQueryData(queryKey)
// ^? number | undefined
```
### Type Parameters
#### TQueryFnData
`TQueryFnData` = `unknown`
#### TError
`TError` = `Error`
#### TData
`TData` = `TQueryFnData`
#### TQueryKey
`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
### Parameters
#### options
[`UndefinedInitialDataOptions`](../type-aliases/UndefinedInitialDataOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\>
The query options to tag with the type from `queryFn`.
### Returns
[`CreateQueryOptions`](../interfaces/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`\> & `object` & `object`
The tagged query options.
================================================
FILE: docs/framework/angular/reference/index.md
================================================
---
id: "@tanstack/angular-query-experimental"
title: "@tanstack/angular-query-experimental"
---
# @tanstack/angular-query-experimental
## Interfaces
- [BaseMutationNarrowing](interfaces/BaseMutationNarrowing.md)
- [BaseQueryNarrowing](interfaces/BaseQueryNarrowing.md)
- [CreateBaseQueryOptions](interfaces/CreateBaseQueryOptions.md)
- [CreateInfiniteQueryOptions](interfaces/CreateInfiniteQueryOptions.md)
- [CreateMutationOptions](interfaces/CreateMutationOptions.md)
- [CreateQueryOptions](interfaces/CreateQueryOptions.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)
- [QueryFeature](interfaces/QueryFeature.md)
## Type Aliases
- [CreateBaseMutationResult](type-aliases/CreateBaseMutationResult.md)
- [CreateBaseQueryResult](type-aliases/CreateBaseQueryResult.md)
- [CreateInfiniteQueryResult](type-aliases/CreateInfiniteQueryResult.md)
- [CreateMutateAsyncFunction](type-aliases/CreateMutateAsyncFunction.md)
- [CreateMutateFunction](type-aliases/CreateMutateFunction.md)
- [CreateMutationResult](type-aliases/CreateMutationResult.md)
- [CreateQueryResult](type-aliases/CreateQueryResult.md)
- [DefinedCreateInfiniteQueryResult](type-aliases/DefinedCreateInfiniteQueryResult.md)
- [DefinedCreateQueryResult](type-aliases/DefinedCreateQueryResult.md)
- [DefinedInitialDataInfiniteOptions](type-aliases/DefinedInitialDataInfiniteOptions.md)
- [DefinedInitialDataOptions](type-aliases/DefinedInitialDataOptions.md)
- [DevtoolsFeature](type-aliases/DevtoolsFeature.md)
- [PersistQueryClientFeature](type-aliases/PersistQueryClientFeature.md)
- [QueriesOptions](type-aliases/QueriesOptions.md)
- [QueriesResults](type-aliases/QueriesResults.md)
- [QueryFeatures](type-aliases/QueryFeatures.md)
- [UndefinedInitialDataInfiniteOptions](type-aliases/UndefinedInitialDataInfiniteOptions.md)
- [UndefinedInitialDataOptions](type-aliases/UndefinedInitialDataOptions.md)
- [UnusedSkipTokenInfiniteOptions](type-aliases/UnusedSkipTokenInfiniteOptions.md)
- [UnusedSkipTokenOptions](type-aliases/UnusedSkipTokenOptions.md)
## Functions
- [infiniteQueryOptions](functions/infiniteQueryOptions.md)
- [injectInfiniteQuery](functions/injectInfiniteQuery.md)
- [injectIsFetching](functions/injectIsFetching.md)
- [injectIsMutating](functions/injectIsMutating.md)
- [injectIsRestoring](functions/injectIsRestoring.md)
- [injectMutation](functions/injectMutation.md)
- [injectMutationState](functions/injectMutationState.md)
- [injectQuery](functions/injectQuery.md)
- [~~injectQueryClient~~](functions/injectQueryClient.md)
- [mutationOptions](functions/mutationOptions.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)
================================================
FILE: docs/framework/angular/reference/interfaces/BaseMutationNarrowing.md
================================================
---
id: BaseMutationNarrowing
title: BaseMutationNarrowing
---
# Interface: BaseMutationNarrowing\
Defined in: [types.ts:190](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L190)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TVariables
`TVariables` = `unknown`
### TOnMutateResult
`TOnMutateResult` = `unknown`
## Properties
### isError
```ts
isError: SignalFunction<(this) => this is CreateMutationResult, { mutate: CreateMutateFunction }> & { mutateAsync: CreateMutateAsyncFunction }>>;
```
Defined in: [types.ts:213](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L213)
***
### isIdle
```ts
isIdle: SignalFunction<(this) => this is CreateMutationResult, { mutate: CreateMutateFunction }> & { mutateAsync: CreateMutateAsyncFunction }>>;
```
Defined in: [types.ts:247](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L247)
***
### isPending
```ts
isPending: SignalFunction<(this) => this is CreateMutationResult, { mutate: CreateMutateFunction }> & { mutateAsync: CreateMutateAsyncFunction }>>;
```
Defined in: [types.ts:230](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L230)
***
### isSuccess
```ts
isSuccess: SignalFunction<(this) => this is CreateMutationResult, { mutate: CreateMutateFunction }> & { mutateAsync: CreateMutateAsyncFunction }>>;
```
Defined in: [types.ts:196](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L196)
================================================
FILE: docs/framework/angular/reference/interfaces/BaseQueryNarrowing.md
================================================
---
id: BaseQueryNarrowing
title: BaseQueryNarrowing
---
# Interface: BaseQueryNarrowing\
Defined in: [types.ts:57](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L57)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
## Properties
### isError()
```ts
isError: (this) => this is CreateBaseQueryResult>;
```
Defined in: [types.ts:65](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L65)
#### Parameters
##### this
[`CreateBaseQueryResult`](../type-aliases/CreateBaseQueryResult.md)\<`TData`, `TError`\>
#### Returns
`this is CreateBaseQueryResult>`
***
### isPending()
```ts
isPending: (this) => this is CreateBaseQueryResult>;
```
Defined in: [types.ts:72](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L72)
#### Parameters
##### this
[`CreateBaseQueryResult`](../type-aliases/CreateBaseQueryResult.md)\<`TData`, `TError`\>
#### Returns
`this is CreateBaseQueryResult>`
***
### isSuccess()
```ts
isSuccess: (this) => this is CreateBaseQueryResult>;
```
Defined in: [types.ts:58](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L58)
#### Parameters
##### this
[`CreateBaseQueryResult`](../type-aliases/CreateBaseQueryResult.md)\<`TData`, `TError`\>
#### Returns
`this is CreateBaseQueryResult>`
================================================
FILE: docs/framework/angular/reference/interfaces/CreateBaseQueryOptions.md
================================================
---
id: CreateBaseQueryOptions
title: CreateBaseQueryOptions
---
# Interface: CreateBaseQueryOptions\
Defined in: [types.ts:21](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L21)
## Extends
- `QueryObserverOptions`\<`TQueryFnData`, `TError`, `TData`, `TQueryData`, `TQueryKey`\>
## Type Parameters
### TQueryFnData
`TQueryFnData` = `unknown`
### TError
`TError` = `DefaultError`
### TData
`TData` = `TQueryFnData`
### TQueryData
`TQueryData` = `TQueryFnData`
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
================================================
FILE: docs/framework/angular/reference/interfaces/CreateInfiniteQueryOptions.md
================================================
---
id: CreateInfiniteQueryOptions
title: CreateInfiniteQueryOptions
---
# Interface: CreateInfiniteQueryOptions\
Defined in: [types.ts:81](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L81)
## Extends
- `OmitKeyof`\<`InfiniteQueryObserverOptions`\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>, `"suspense"`\>
## Type Parameters
### TQueryFnData
`TQueryFnData` = `unknown`
### TError
`TError` = `DefaultError`
### TData
`TData` = `TQueryFnData`
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
### TPageParam
`TPageParam` = `unknown`
================================================
FILE: docs/framework/angular/reference/interfaces/CreateMutationOptions.md
================================================
---
id: CreateMutationOptions
title: CreateMutationOptions
---
# Interface: CreateMutationOptions\
Defined in: [types.ts:132](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L132)
## Extends
- `OmitKeyof`\<`MutationObserverOptions`\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>, `"_defaulted"`\>
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TVariables
`TVariables` = `void`
### TOnMutateResult
`TOnMutateResult` = `unknown`
================================================
FILE: docs/framework/angular/reference/interfaces/CreateQueryOptions.md
================================================
---
id: CreateQueryOptions
title: CreateQueryOptions
---
# Interface: CreateQueryOptions\
Defined in: [types.ts:35](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L35)
## Extends
- `OmitKeyof`\<[`CreateBaseQueryOptions`](CreateBaseQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryFnData`, `TQueryKey`\>, `"suspense"`\>
## Type Parameters
### TQueryFnData
`TQueryFnData` = `unknown`
### TError
`TError` = `DefaultError`
### TData
`TData` = `TQueryFnData`
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
================================================
FILE: docs/framework/angular/reference/interfaces/InjectInfiniteQueryOptions.md
================================================
---
id: InjectInfiniteQueryOptions
title: InjectInfiniteQueryOptions
---
# Interface: InjectInfiniteQueryOptions
Defined in: [inject-infinite-query.ts:25](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L25)
## Properties
### injector?
```ts
optional injector: Injector;
```
Defined in: [inject-infinite-query.ts:31](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-infinite-query.ts#L31)
The `Injector` in which to create the infinite query.
If this is not provided, the current injection context will be used instead (via `inject`).
================================================
FILE: docs/framework/angular/reference/interfaces/InjectIsFetchingOptions.md
================================================
---
id: InjectIsFetchingOptions
title: InjectIsFetchingOptions
---
# Interface: InjectIsFetchingOptions
Defined in: [inject-is-fetching.ts:13](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-fetching.ts#L13)
## Properties
### injector?
```ts
optional injector: Injector;
```
Defined in: [inject-is-fetching.ts:19](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-fetching.ts#L19)
The `Injector` in which to create the isFetching signal.
If this is not provided, the current injection context will be used instead (via `inject`).
================================================
FILE: docs/framework/angular/reference/interfaces/InjectIsMutatingOptions.md
================================================
---
id: InjectIsMutatingOptions
title: InjectIsMutatingOptions
---
# Interface: InjectIsMutatingOptions
Defined in: [inject-is-mutating.ts:13](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-mutating.ts#L13)
## Properties
### injector?
```ts
optional injector: Injector;
```
Defined in: [inject-is-mutating.ts:19](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-is-mutating.ts#L19)
The `Injector` in which to create the isMutating signal.
If this is not provided, the current injection context will be used instead (via `inject`).
================================================
FILE: docs/framework/angular/reference/interfaces/InjectMutationOptions.md
================================================
---
id: InjectMutationOptions
title: InjectMutationOptions
---
# Interface: InjectMutationOptions
Defined in: [inject-mutation.ts:28](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L28)
## Properties
### injector?
```ts
optional injector: Injector;
```
Defined in: [inject-mutation.ts:34](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L34)
The `Injector` in which to create the mutation.
If this is not provided, the current injection context will be used instead (via `inject`).
================================================
FILE: docs/framework/angular/reference/interfaces/InjectMutationStateOptions.md
================================================
---
id: InjectMutationStateOptions
title: InjectMutationStateOptions
---
# Interface: InjectMutationStateOptions
Defined in: [inject-mutation-state.ts:45](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation-state.ts#L45)
## Properties
### injector?
```ts
optional injector: Injector;
```
Defined in: [inject-mutation-state.ts:51](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation-state.ts#L51)
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`).
================================================
FILE: docs/framework/angular/reference/interfaces/InjectQueryOptions.md
================================================
---
id: InjectQueryOptions
title: InjectQueryOptions
---
# Interface: InjectQueryOptions
Defined in: [inject-query.ts:20](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L20)
## Properties
### injector?
```ts
optional injector: Injector;
```
Defined in: [inject-query.ts:26](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-query.ts#L26)
The `Injector` in which to create the query.
If this is not provided, the current injection context will be used instead (via `inject`).
================================================
FILE: docs/framework/angular/reference/interfaces/QueryFeature.md
================================================
---
id: QueryFeature
title: QueryFeature
---
# Interface: QueryFeature\
Defined in: [providers.ts:135](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L135)
Helper type to represent a Query feature.
## Type Parameters
### TFeatureKind
`TFeatureKind` *extends* `QueryFeatureKind`
## Properties
### ɵkind
```ts
ɵkind: TFeatureKind;
```
Defined in: [providers.ts:136](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L136)
***
### ɵproviders
```ts
ɵproviders: Provider[];
```
Defined in: [providers.ts:137](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L137)
================================================
FILE: docs/framework/angular/reference/type-aliases/CreateBaseMutationResult.md
================================================
---
id: CreateBaseMutationResult
title: CreateBaseMutationResult
---
# Type Alias: CreateBaseMutationResult\
```ts
type CreateBaseMutationResult = Override, {
mutate: CreateMutateFunction;
}> & object;
```
Defined in: [types.ts:160](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L160)
## Type Declaration
### mutateAsync
```ts
mutateAsync: CreateMutateAsyncFunction;
```
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TVariables
`TVariables` = `unknown`
### TOnMutateResult
`TOnMutateResult` = `unknown`
================================================
FILE: docs/framework/angular/reference/type-aliases/CreateBaseQueryResult.md
================================================
---
id: CreateBaseQueryResult
title: CreateBaseQueryResult
---
# Type Alias: CreateBaseQueryResult\
```ts
type CreateBaseQueryResult = BaseQueryNarrowing & MapToSignals>;
```
Defined in: [types.ts:98](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L98)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TState
`TState` = `QueryObserverResult`\<`TData`, `TError`\>
================================================
FILE: docs/framework/angular/reference/type-aliases/CreateInfiniteQueryResult.md
================================================
---
id: CreateInfiniteQueryResult
title: CreateInfiniteQueryResult
---
# Type Alias: CreateInfiniteQueryResult\
```ts
type CreateInfiniteQueryResult = BaseQueryNarrowing & MapToSignals>;
```
Defined in: [types.ts:117](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L117)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
================================================
FILE: docs/framework/angular/reference/type-aliases/CreateMutateAsyncFunction.md
================================================
---
id: CreateMutateAsyncFunction
title: CreateMutateAsyncFunction
---
# Type Alias: CreateMutateAsyncFunction\
```ts
type CreateMutateAsyncFunction = MutateFunction;
```
Defined in: [types.ts:153](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L153)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TVariables
`TVariables` = `void`
### TOnMutateResult
`TOnMutateResult` = `unknown`
================================================
FILE: docs/framework/angular/reference/type-aliases/CreateMutateFunction.md
================================================
---
id: CreateMutateFunction
title: CreateMutateFunction
---
# Type Alias: CreateMutateFunction()\
```ts
type CreateMutateFunction = (...args) => void;
```
Defined in: [types.ts:142](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L142)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TVariables
`TVariables` = `void`
### TOnMutateResult
`TOnMutateResult` = `unknown`
## Parameters
### args
...`Parameters`\<`MutateFunction`\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>\>
## Returns
`void`
================================================
FILE: docs/framework/angular/reference/type-aliases/CreateMutationResult.md
================================================
---
id: CreateMutationResult
title: CreateMutationResult
---
# Type Alias: CreateMutationResult\
```ts
type CreateMutationResult = BaseMutationNarrowing & MapToSignals>;
```
Defined in: [types.ts:266](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L266)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TVariables
`TVariables` = `unknown`
### TOnMutateResult
`TOnMutateResult` = `unknown`
### TState
`TState` = `CreateStatusBasedMutationResult`\<[`CreateBaseMutationResult`](CreateBaseMutationResult.md)\[`"status"`\], `TData`, `TError`, `TVariables`, `TOnMutateResult`\>
================================================
FILE: docs/framework/angular/reference/type-aliases/CreateQueryResult.md
================================================
---
id: CreateQueryResult
title: CreateQueryResult
---
# Type Alias: CreateQueryResult\
```ts
type CreateQueryResult = CreateBaseQueryResult;
```
Defined in: [types.ts:105](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L105)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
================================================
FILE: docs/framework/angular/reference/type-aliases/DefinedCreateInfiniteQueryResult.md
================================================
---
id: DefinedCreateInfiniteQueryResult
title: DefinedCreateInfiniteQueryResult
---
# Type Alias: DefinedCreateInfiniteQueryResult\
```ts
type DefinedCreateInfiniteQueryResult = MapToSignals;
```
Defined in: [types.ts:123](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L123)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TDefinedInfiniteQueryObserver
`TDefinedInfiniteQueryObserver` = `DefinedInfiniteQueryObserverResult`\<`TData`, `TError`\>
================================================
FILE: docs/framework/angular/reference/type-aliases/DefinedCreateQueryResult.md
================================================
---
id: DefinedCreateQueryResult
title: DefinedCreateQueryResult
---
# Type Alias: DefinedCreateQueryResult\
```ts
type DefinedCreateQueryResult = BaseQueryNarrowing & MapToSignals>;
```
Defined in: [types.ts:110](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/types.ts#L110)
## Type Parameters
### TData
`TData` = `unknown`
### TError
`TError` = `DefaultError`
### TState
`TState` = `DefinedQueryObserverResult`\<`TData`, `TError`\>
================================================
FILE: docs/framework/angular/reference/type-aliases/DefinedInitialDataInfiniteOptions.md
================================================
---
id: DefinedInitialDataInfiniteOptions
title: DefinedInitialDataInfiniteOptions
---
# Type Alias: DefinedInitialDataInfiniteOptions\
```ts
type DefinedInitialDataInfiniteOptions = CreateInfiniteQueryOptions & object;
```
Defined in: [infinite-query-options.ts:62](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L62)
## Type Declaration
### initialData
```ts
initialData:
| NonUndefinedGuard>
| () => NonUndefinedGuard>
| undefined;
```
## Type Parameters
### TQueryFnData
`TQueryFnData`
### TError
`TError` = `DefaultError`
### TData
`TData` = `InfiniteData`\<`TQueryFnData`\>
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
### TPageParam
`TPageParam` = `unknown`
================================================
FILE: docs/framework/angular/reference/type-aliases/DefinedInitialDataOptions.md
================================================
---
id: DefinedInitialDataOptions
title: DefinedInitialDataOptions
---
# Type Alias: DefinedInitialDataOptions\
```ts
type DefinedInitialDataOptions = Omit, "queryFn"> & object;
```
Defined in: [query-options.ts:40](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L40)
## Type Declaration
### initialData
```ts
initialData:
| NonUndefinedGuard
| () => NonUndefinedGuard;
```
### queryFn?
```ts
optional queryFn: QueryFunction;
```
## Type Parameters
### TQueryFnData
`TQueryFnData` = `unknown`
### TError
`TError` = `DefaultError`
### TData
`TData` = `TQueryFnData`
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
================================================
FILE: docs/framework/angular/reference/type-aliases/DevtoolsFeature.md
================================================
---
id: DevtoolsFeature
title: DevtoolsFeature
---
# Type Alias: DevtoolsFeature
```ts
type DevtoolsFeature = QueryFeature<"Devtools">;
```
Defined in: [providers.ts:158](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L158)
A type alias that represents a feature which enables developer tools.
The type is used to describe the return value of the `withDevtools` function.
## See
withDevtools
================================================
FILE: docs/framework/angular/reference/type-aliases/PersistQueryClientFeature.md
================================================
---
id: PersistQueryClientFeature
title: PersistQueryClientFeature
---
# Type Alias: PersistQueryClientFeature
```ts
type PersistQueryClientFeature = QueryFeature<"PersistQueryClient">;
```
Defined in: [providers.ts:164](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L164)
A type alias that represents a feature which enables persistence.
The type is used to describe the return value of the `withPersistQueryClient` function.
================================================
FILE: docs/framework/angular/reference/type-aliases/QueriesOptions.md
================================================
---
id: QueriesOptions
title: QueriesOptions
---
# Type Alias: QueriesOptions\
```ts
type QueriesOptions = TDepth["length"] extends MAXIMUM_DEPTH ? QueryObserverOptionsForCreateQueries[] : T extends [] ? [] : T extends [infer Head] ? [...TResults, GetCreateQueryOptionsForCreateQueries] : T extends [infer Head, ...(infer Tails)] ? QueriesOptions<[...Tails], [...TResults, GetCreateQueryOptionsForCreateQueries], [...TDepth, 1]> : ReadonlyArray extends T ? T : T extends QueryObserverOptionsForCreateQueries[] ? QueryObserverOptionsForCreateQueries[] : QueryObserverOptionsForCreateQueries[];
```
Defined in: [inject-queries.ts:144](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L144)
QueriesOptions reducer recursively unwraps function arguments to infer/enforce type param
## Type Parameters
### T
`T` *extends* `any`[]
### TResults
`TResults` *extends* `any`[] = \[\]
### TDepth
`TDepth` *extends* `ReadonlyArray`\<`number`\> = \[\]
================================================
FILE: docs/framework/angular/reference/type-aliases/QueriesResults.md
================================================
---
id: QueriesResults
title: QueriesResults
---
# Type Alias: QueriesResults\
```ts
type QueriesResults = TDepth["length"] extends MAXIMUM_DEPTH ? CreateQueryResult[] : T extends [] ? [] : T extends [infer Head] ? [...TResults, GetCreateQueryResult] : T extends [infer Head, ...(infer Tails)] ? QueriesResults<[...Tails], [...TResults, GetCreateQueryResult], [...TDepth, 1]> : { [K in keyof T]: GetCreateQueryResult };
```
Defined in: [inject-queries.ts:186](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-queries.ts#L186)
QueriesResults reducer recursively maps type param to results
## Type Parameters
### T
`T` *extends* `any`[]
### TResults
`TResults` *extends* `any`[] = \[\]
### TDepth
`TDepth` *extends* `ReadonlyArray`\<`number`\> = \[\]
================================================
FILE: docs/framework/angular/reference/type-aliases/QueryFeatures.md
================================================
---
id: QueryFeatures
title: QueryFeatures
---
# Type Alias: QueryFeatures
```ts
type QueryFeatures =
| DevtoolsFeature
| PersistQueryClientFeature;
```
Defined in: [providers.ts:173](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/providers.ts#L173)
A type alias that represents all Query features available for use with `provideTanStackQuery`.
Features can be enabled by adding special functions to the `provideTanStackQuery` call.
See documentation for each symbol to find corresponding function name. See also `provideTanStackQuery`
documentation on how to use those functions.
## See
[provideTanStackQuery](../functions/provideTanStackQuery.md)
================================================
FILE: docs/framework/angular/reference/type-aliases/UndefinedInitialDataInfiniteOptions.md
================================================
---
id: UndefinedInitialDataInfiniteOptions
title: UndefinedInitialDataInfiniteOptions
---
# Type Alias: UndefinedInitialDataInfiniteOptions\
```ts
type UndefinedInitialDataInfiniteOptions = CreateInfiniteQueryOptions & object;
```
Defined in: [infinite-query-options.ts:13](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L13)
## Type Declaration
### initialData?
```ts
optional initialData:
| NonUndefinedGuard>
| InitialDataFunction>>;
```
## Type Parameters
### TQueryFnData
`TQueryFnData`
### TError
`TError` = `DefaultError`
### TData
`TData` = `InfiniteData`\<`TQueryFnData`\>
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
### TPageParam
`TPageParam` = `unknown`
================================================
FILE: docs/framework/angular/reference/type-aliases/UndefinedInitialDataOptions.md
================================================
---
id: UndefinedInitialDataOptions
title: UndefinedInitialDataOptions
---
# Type Alias: UndefinedInitialDataOptions\
```ts
type UndefinedInitialDataOptions = CreateQueryOptions & object;
```
Defined in: [query-options.ts:13](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L13)
## Type Declaration
### initialData?
```ts
optional initialData:
| InitialDataFunction>
| NonUndefinedGuard;
```
## Type Parameters
### TQueryFnData
`TQueryFnData` = `unknown`
### TError
`TError` = `DefaultError`
### TData
`TData` = `TQueryFnData`
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
================================================
FILE: docs/framework/angular/reference/type-aliases/UnusedSkipTokenInfiniteOptions.md
================================================
---
id: UnusedSkipTokenInfiniteOptions
title: UnusedSkipTokenInfiniteOptions
---
# Type Alias: UnusedSkipTokenInfiniteOptions\
```ts
type UnusedSkipTokenInfiniteOptions = OmitKeyof, "queryFn"> & object;
```
Defined in: [infinite-query-options.ts:34](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/infinite-query-options.ts#L34)
## Type Declaration
### queryFn?
```ts
optional queryFn: Exclude["queryFn"], SkipToken | undefined>;
```
## Type Parameters
### TQueryFnData
`TQueryFnData`
### TError
`TError` = `DefaultError`
### TData
`TData` = `InfiniteData`\<`TQueryFnData`\>
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
### TPageParam
`TPageParam` = `unknown`
================================================
FILE: docs/framework/angular/reference/type-aliases/UnusedSkipTokenOptions.md
================================================
---
id: UnusedSkipTokenOptions
title: UnusedSkipTokenOptions
---
# Type Alias: UnusedSkipTokenOptions\
```ts
type UnusedSkipTokenOptions = OmitKeyof, "queryFn"> & object;
```
Defined in: [query-options.ts:25](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/query-options.ts#L25)
## Type Declaration
### queryFn?
```ts
optional queryFn: Exclude["queryFn"], SkipToken | undefined>;
```
## Type Parameters
### TQueryFnData
`TQueryFnData` = `unknown`
### TError
`TError` = `DefaultError`
### TData
`TData` = `TQueryFnData`
### TQueryKey
`TQueryKey` *extends* `QueryKey` = `QueryKey`
================================================
FILE: docs/framework/angular/typescript.md
================================================
---
id: typescript
title: TypeScript
ref: docs/framework/react/typescript.md
replace:
{
'useQuery': 'injectQuery',
'useMutation': 'injectMutation',
'react-query': 'angular-query-experimental',
'public API of React Query': 'public API of TanStack Query and - after the experimental phase, the angular-query package',
'still follows': 'still follow',
'React Query': 'TanStack Query',
'`success`': '`isSuccess()`',
'function:': 'function.',
}
---
[//]: # 'TypeInference1'
```angular-ts
@Component({
// ...
template: `@let data = query.data();`,
// ^? data: number | undefined
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve(5),
}))
}
```
[//]: # 'TypeInference1'
[//]: # 'TypeInference2'
```angular-ts
@Component({
// ...
template: `@let data = query.data();`,
// ^? data: string | undefined
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve(5),
select: (data) => data.toString(),
}))
}
```
[//]: # 'TypeInference2'
[//]: # 'TypeInference3'
In this example we pass Group[] to the type parameter of HttpClient's `get` method.
```angular-ts
@Component({
template: `@let data = query.data();`,
// ^? data: Group[] | undefined
})
class MyComponent {
http = inject(HttpClient)
query = injectQuery(() => ({
queryKey: ['groups'],
queryFn: () => lastValueFrom(this.http.get('/groups')),
}))
}
```
[//]: # 'TypeInference3'
[//]: # 'TypeNarrowing'
```angular-ts
@Component({
// ...
template: `
@if (query.isSuccess()) {
@let data = query.data();
// ^? data: number
}
`,
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['test'],
queryFn: () => Promise.resolve(5),
}))
}
```
> TypeScript currently does not support discriminated unions on object methods. Narrowing on signal fields on objects such as query results only works on signals returning a boolean. Prefer using `isSuccess()` and similar boolean status signals over `status() === 'success'`.
[//]: # 'TypeNarrowing'
[//]: # 'TypingError'
```angular-ts
@Component({
// ...
template: `@let error = query.error();`,
// ^? error: Error | null
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['groups'],
queryFn: fetchGroups,
}))
}
```
[//]: # 'TypingError'
[//]: # 'TypingError2'
```angular-ts
@Component({
// ...
template: `@let error = query.error();`,
// ^? error: string | null
})
class MyComponent {
query = injectQuery(() => ({
queryKey: ['groups'],
queryFn: fetchGroups,
}))
}
```
[//]: # 'TypingError2'
[//]: # 'TypingError3'
```ts
import axios from 'axios'
query = injectQuery(() => ({ queryKey: ['groups'], queryFn: fetchGroups }))
computed(() => {
const error = query.error()
// ^? error: Error | null
if (axios.isAxiosError(error)) {
error
// ^? const error: AxiosError
}
})
```
[//]: # 'TypingError3'
[//]: # 'RegisterErrorType'
```ts
import '@tanstack/angular-query-experimental'
declare module '@tanstack/angular-query-experimental' {
interface Register {
// Use unknown so call sites must narrow explicitly.
defaultError: unknown
}
}
const query = injectQuery(() => ({
queryKey: ['groups'],
queryFn: fetchGroups,
}))
computed(() => {
const error = query.error()
// ^? error: unknown | null
})
```
[//]: # 'RegisterErrorType'
[//]: # 'TypingQueryOptions'
## Typing Query Options
If you inline query options into `injectQuery`, you'll get automatic type inference. However, you might want to extract the query options into a separate function to share them between `injectQuery` and e.g. `prefetchQuery` or manage them in a service. In that case, you'd lose type inference. To get it back, you can use the `queryOptions` helper:
```ts
@Injectable({
providedIn: 'root',
})
export class QueriesService {
private http = inject(HttpClient)
post(postId: number) {
return queryOptions({
queryKey: ['post', postId],
queryFn: () => {
return lastValueFrom(
this.http.get(
`https://jsonplaceholder.typicode.com/posts/${postId}`,
),
)
},
})
}
}
@Component({
// ...
})
export class Component {
queryClient = inject(QueryClient)
postId = signal(1)
queries = inject(QueriesService)
optionsSignal = computed(() => this.queries.post(this.postId()))
postQuery = injectQuery(() => this.queries.post(1))
postQuery = injectQuery(() => this.queries.post(this.postId()))
// You can also pass a signal which returns query options
postQuery = injectQuery(this.optionsSignal)
someMethod() {
this.queryClient.prefetchQuery(this.queries.post(23))
}
}
```
Further, the `queryKey` returned from `queryOptions` knows about the `queryFn` associated with it, and we can leverage that type information to make functions like `queryClient.getQueryData` aware of those types as well:
```ts
data = this.queryClient.getQueryData(groupOptions().queryKey)
// ^? data: Post | undefined
```
Without `queryOptions`, the type of data would be unknown, unless we'd pass a type parameter:
```ts
data = queryClient.getQueryData(['post', 1])
```
## Typing Mutation Options
Similarly to `queryOptions`, you can use `mutationOptions` to extract mutation options into a separate function:
```ts
export class QueriesService {
private http = inject(HttpClient)
updatePost(id: number) {
return mutationOptions({
mutationFn: (post: Post) => Promise.resolve(post),
mutationKey: ['updatePost', id],
onSuccess: (newPost) => {
// ^? newPost: Post
this.queryClient.setQueryData(['posts', id], newPost)
},
})
}
}
```
[//]: # 'TypingQueryOptions'
[//]: # 'Materials'
[//]: # 'Materials'
================================================
FILE: docs/framework/angular/zoneless.md
================================================
---
id: zoneless
title: Zoneless Angular
---
Because the Angular adapter for TanStack Query is built on signals, it fully supports Zoneless!
Among Zoneless benefits are improved performance and debugging experience. For details see the [Angular documentation](https://angular.dev/guide/zoneless).
> Besides Zoneless, ZoneJS change detection is also fully supported.
> When using Zoneless, ensure you are on Angular v19 or later to take advantage of the `PendingTasks` integration that keeps `ApplicationRef.whenStable()` in sync with ongoing queries and mutations.
================================================
FILE: docs/framework/preact/devtools.md
================================================
---
id: devtools
title: Devtools
---
Wave your hands in the air and shout hooray because Preact Query comes with dedicated devtools! 🥳
When you begin your Preact Query journey, you'll want these devtools by your side. They help visualize all of the inner workings of Preact Query and will likely save you hours of debugging if you find yourself in a pinch!
> For Chrome, Firefox, and Edge users: Third-party browser extensions are available for debugging TanStack Query directly in browser DevTools. These provide the same functionality as the framework-specific devtools packages:
>
> - [Devtools for Chrome](https://chromewebstore.google.com/detail/tanstack-query-devtools/annajfchloimdhceglpgglpeepfghfai)
> - [Devtools for Firefox](https://addons.mozilla.org/en-US/firefox/addon/tanstack-query-devtools/)
> - [Devtools for Edge](https://microsoftedge.microsoft.com/addons/detail/tanstack-query-devtools/edmdpkgkacmjopodhfolmphdenmddobj)
## Install and Import the Devtools
The devtools are a separate package that you need to install:
```bash
npm i @tanstack/preact-query-devtools
```
or
```bash
pnpm add @tanstack/preact-query-devtools
```
or
```bash
yarn add @tanstack/preact-query-devtools
```
or
```bash
bun add @tanstack/preact-query-devtools
```
You can import the devtools like this:
```tsx
import { PreactQueryDevtools } from '@tanstack/preact-query-devtools'
```
By default, Preact Query Devtools are only included in bundles when `process.env.NODE_ENV === 'development'`, so you don't need to worry about excluding them during a production build.
## Floating Mode
Floating Mode will mount the devtools as a fixed, floating element in your app and provide a toggle in the corner of the screen to show and hide the devtools. This toggle state will be stored and remembered in localStorage across reloads.
Place the following code as high in your Preact app as you can. The closer it is to the root of the page, the better it will work!
```tsx
import { PreactQueryDevtools } from '@tanstack/preact-query-devtools'
function App() {
return (
{/* The rest of your application */}
)
}
```
### Options
- `initialIsOpen: boolean`
- Set this `true` if you want the dev tools to default to being open
- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right"`
- Defaults to `bottom-right`
- The position of the Preact Query logo to open and close the devtools panel
- `position?: "top" | "bottom" | "left" | "right"`
- Defaults to `bottom`
- The position of the Preact Query devtools panel
- `client?: QueryClient`,
- Use this to use a custom QueryClient. Otherwise, the one from the nearest context will be used.
- `errorTypes?: { name: string; initializer: (query: Query) => TError}`
- Use this to predefine some errors that can be triggered on your queries. Initializer will be called (with the specific query) when that error is toggled on from the UI. It must return an Error.
- `styleNonce?: string`
- Use this to pass a nonce to the style tag that is added to the document head. This is useful if you are using a Content Security Policy (CSP) nonce to allow inline styles.
- `shadowDOMTarget?: ShadowRoot`
- Default behavior will apply the devtool's styles to the head tag within the DOM.
- Use this to pass a shadow DOM target to the devtools so that the styles will be applied within the shadow DOM instead of within the head tag in the light DOM.
================================================
FILE: docs/framework/preact/graphql.md
================================================
---
id: graphql
title: GraphQL
ref: docs/framework/react/graphql.md
replace: { 'react-query': 'preact-query', 'React': 'Preact' }
---
================================================
FILE: docs/framework/preact/guides/background-fetching-indicators.md
================================================
---
id: background-fetching-indicators
title: Background Fetching Indicators
ref: docs/framework/react/guides/background-fetching-indicators.md
replace: { 'react-query': 'preact-query', 'React': 'Preact' }
---
================================================
FILE: docs/framework/preact/guides/caching.md
================================================
---
id: caching
title: Caching Examples
ref: docs/framework/react/guides/caching.md
replace: { 'react-query': 'preact-query', 'React': 'Preact' }
---
================================================
FILE: docs/framework/preact/guides/default-query-function.md
================================================
---
id: default-query-function
title: Default Query Function
ref: docs/framework/react/guides/default-query-function.md
replace: { 'react-query': 'preact-query', 'React': 'Preact' }
---
================================================
FILE: docs/framework/preact/guides/dependent-queries.md
================================================
---
id: dependent-queries
title: Dependent Queries
ref: docs/framework/react/guides/dependent-queries.md
replace: { 'react-query': 'preact-query', 'React': 'Preact' }
---
================================================
FILE: docs/framework/preact/guides/disabling-queries.md
================================================
---
id: disabling-queries
title: Disabling/Pausing Queries
ref: docs/framework/react/guides/disabling-queries.md
replace: { 'react-query': 'preact-query', 'React': 'Preact' }
---
[//]: # 'Example2'
```tsx
function Todos() {
const [filter, setFilter] = useState('')
const { data } = useQuery({
queryKey: ['todos', filter],
queryFn: () => fetchTodos(filter),
// ⬇️ disabled as long as the filter is empty
enabled: !!filter,
})
return (
// 🚀 applying the filter will enable and execute the query
{data && }
)
}
```
[//]: # 'Example2'
[//]: # 'Example3'
```tsx
import { skipToken, useQuery } from '@tanstack/preact-query'
function Todos() {
const [filter, setFilter] = useState()
const { data } = useQuery({
queryKey: ['todos', filter],
// ⬇️ disabled as long as the filter is undefined or empty
queryFn: filter ? () => fetchTodos(filter) : skipToken,
})
return (
// 🚀 applying the filter will enable and execute the query
{data && }