`)}
+ `,
+ )}
+
+
+ `
+ }
+}
+```
+
+## Page Parameters
+
+`initialPageParam` is required. `getNextPageParam` decides whether another page exists and what value should be passed as `pageParam` to the next query function call.
+
+```ts
+createInfiniteQueryController(this, {
+ queryKey: ['projects'],
+ queryFn: ({ pageParam }) => fetchProjectsPage(pageParam),
+ initialPageParam: 1,
+ getNextPageParam: (lastPage) =>
+ lastPage.hasMore ? lastPage.page + 1 : undefined,
+})
+```
+
+Returning `undefined` or `null` means there is no next page.
+
+## Avoid Overlapping Fetches
+
+There is one ongoing fetch for an infinite query cache entry. If you call `fetchNextPage` while a background refetch is running, you can overwrite data. Disable the button or check `!query.isFetching` before loading more:
+
+```ts
+if (query.hasNextPage && !query.isFetching) {
+ this.projects.fetchNextPage()
+}
+```
+
+## Paginated Alternative
+
+If your UI shows one page at a time, a normal query with a page in the key can be a better fit. The [Pagination example](../examples/pagination) uses `createQueryController`, `placeholderData: keepPreviousData`, prefetching, and mutations to demonstrate that pattern.
diff --git a/docs/framework/lit/guides/mutations.md b/docs/framework/lit/guides/mutations.md
new file mode 100644
index 00000000000..8e5c3fdfa42
--- /dev/null
+++ b/docs/framework/lit/guides/mutations.md
@@ -0,0 +1,166 @@
+---
+id: mutations
+title: Mutations
+---
+
+Unlike queries, mutations are used to create, update, delete, or otherwise perform server side effects. In Lit, use [`createMutationController`](../reference/functions/createMutationController.md).
+
+```ts
+import { LitElement, html } from 'lit'
+import {
+ QueryClient,
+ QueryClientProvider,
+ createMutationController,
+ createQueryController,
+} from '@tanstack/lit-query'
+
+const queryClient = new QueryClient()
+
+class AppQueryProvider extends QueryClientProvider {
+ constructor() {
+ super()
+ this.client = queryClient
+ }
+}
+
+customElements.define('app-query-provider', AppQueryProvider)
+
+class TodosView extends LitElement {
+ private readonly todos = createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+ })
+
+ private readonly addTodo = createMutationController(this, {
+ mutationFn: createTodo,
+ onSuccess: async () => {
+ await queryClient.invalidateQueries({ queryKey: ['todos'] })
+ },
+ })
+
+ render() {
+ const query = this.todos()
+ const mutation = this.addTodo()
+ const todos = query.data ?? []
+
+ return html`
+ ${mutation.isError ? html`
${mutation.error.message}
` : null}
+ ${mutation.isSuccess ? html`
Todo added
` : null}
+
+
+
+
+ ${todos.map((todo) => html`
${todo.title}
`)}
+
+ `
+ }
+}
+
+customElements.define('todos-view', TodosView)
+```
+
+Render the element under the provider so the controllers can resolve the same `QueryClient` from Lit context:
+
+```html
+
+
+
+```
+
+## Mutation States
+
+A mutation can be in one of these primary states:
+
+- `isIdle` or `status === 'idle'`: no mutation has run or it has been reset
+- `isPending` or `status === 'pending'`: the mutation is running
+- `isError` or `status === 'error'`: the mutation failed and `error` is available
+- `isSuccess` or `status === 'success'`: the mutation finished and `data` is available
+
+## Variables
+
+Pass variables to the mutation function by calling `mutate`:
+
+```ts
+this.addTodo.mutate({
+ title: this.nextTitle,
+})
+```
+
+`mutate` throws synchronously if the controller cannot resolve a `QueryClient`, such as when the element is not under a connected `QueryClientProvider` and no explicit client was passed. `mutateAsync` reports the same setup problem as a rejected promise.
+
+Use `mutateAsync` when you want a promise:
+
+```ts
+try {
+ const created = await this.addTodo.mutateAsync({ title: this.nextTitle })
+ this.nextTitle = created.title
+} catch (error) {
+ this.errorMessage = String(error)
+}
+```
+
+## Resetting Mutation State
+
+The accessor includes `reset`:
+
+```ts
+html`
+ ${mutation.isError
+ ? html``
+ : null}
+`
+```
+
+## Side Effects
+
+Mutation options support `onMutate`, `onError`, `onSuccess`, and `onSettled`. The pagination example passes an explicit `queryClient` to the controller and uses the same in-scope client for optimistic updates and rollback:
+
+```ts
+private readonly favoriteMutation = createMutationController(
+ this,
+ {
+ mutationKey: ['toggle-project-favorite'],
+ mutationFn: async (input) => {
+ const response = await toggleProjectFavoriteOnServer(input)
+ return response.project
+ },
+ onMutate: async (variables) => {
+ await queryClient.cancelQueries({ queryKey: ['projects'] })
+ const snapshots = queryClient.getQueriesData({
+ queryKey: ['projects'],
+ })
+
+ for (const [key, existing] of snapshots) {
+ if (!existing) continue
+
+ queryClient.setQueryData(key, {
+ ...existing,
+ projects: existing.projects.map((project) =>
+ project.id === variables.id
+ ? { ...project, isFavorite: variables.isFavorite }
+ : project,
+ ),
+ })
+ }
+
+ return { snapshots }
+ },
+ onError: (_error, _variables, context) => {
+ for (const [key, snapshot] of context?.snapshots ?? []) {
+ queryClient.setQueryData(key, snapshot)
+ }
+ },
+ onSettled: async () => {
+ await queryClient.invalidateQueries({ queryKey: ['projects'] })
+ },
+ },
+ queryClient,
+)
+```
+
+For the exact runnable flow, see the [Pagination example](../examples/pagination).
diff --git a/docs/framework/lit/guides/parallel-queries.md b/docs/framework/lit/guides/parallel-queries.md
new file mode 100644
index 00000000000..2d9bf967f7b
--- /dev/null
+++ b/docs/framework/lit/guides/parallel-queries.md
@@ -0,0 +1,134 @@
+---
+id: parallel-queries
+title: Parallel Queries
+---
+
+Parallel queries are queries that run at the same time so the UI does not wait for one request before starting the next.
+
+## Manual Parallel Queries
+
+When the number of queries is fixed, create multiple query controllers on the same host. They will all subscribe when the host connects.
+
+```ts
+import { LitElement, html } from 'lit'
+import { createQueryController } from '@tanstack/lit-query'
+
+class DashboardView extends LitElement {
+ private readonly users = createQueryController(this, {
+ queryKey: ['users'],
+ queryFn: fetchUsers,
+ })
+
+ private readonly teams = createQueryController(this, {
+ queryKey: ['teams'],
+ queryFn: fetchTeams,
+ })
+
+ private readonly projects = createQueryController(this, {
+ queryKey: ['projects'],
+ queryFn: fetchProjects,
+ })
+
+ render() {
+ const users = this.users()
+ const teams = this.teams()
+ const projects = this.projects()
+
+ if (users.isPending || teams.isPending || projects.isPending) {
+ return html`Loading...`
+ }
+
+ if (users.isError || teams.isError || projects.isError) {
+ return html`Unable to load dashboard`
+ }
+
+ return html`
+
+ `
+ }
+}
+```
+
+Each controller receives the same `ReactiveControllerHost`. If no explicit `QueryClient` is passed, each controller resolves the nearest connected `QueryClientProvider`.
+
+## Dynamic Parallel Queries
+
+When the number of queries changes with host state, use [`createQueriesController`](../reference/functions/createQueriesController.md). It accepts a `queries` array and returns an accessor for the array of query results.
+
+Use an options getter when the query list depends on reactive host fields:
+
+```ts
+import { LitElement, html } from 'lit'
+import { createQueriesController } from '@tanstack/lit-query'
+
+class UsersDetails extends LitElement {
+ static properties = {
+ userIds: { attribute: false },
+ }
+
+ userIds: Array = []
+
+ private readonly users = createQueriesController(this, () => ({
+ queries: this.userIds.map((id) => ({
+ queryKey: ['user', id],
+ queryFn: () => fetchUserById(id),
+ })),
+ }))
+
+ render() {
+ const userQueries = this.users()
+
+ return html`
+
+ ${userQueries.map((query, index) => {
+ if (query.isPending) return html`
Loading...
`
+ if (query.isError) return html`
Error loading user
`
+
+ return html`
${this.userIds[index]}: ${query.data.name}
`
+ })}
+
+ `
+ }
+}
+```
+
+The order of the results matches the order of the input queries.
+
+## Combining Results
+
+Use `combine` when a component wants one derived value instead of an array of query results:
+
+```ts
+private readonly dashboard = createQueriesController(this, {
+ queries: [
+ { queryKey: ['stats'], queryFn: fetchStats },
+ { queryKey: ['projects'], queryFn: fetchProjects },
+ ],
+ combine: ([stats, projects]) => ({
+ activeUsers: stats.data?.activeUsers ?? 0,
+ projects: projects.data ?? [],
+ isPending: stats.isPending || projects.isPending,
+ isError: stats.isError || projects.isError,
+ }),
+})
+```
+
+```ts
+render() {
+ const dashboard = this.dashboard()
+
+ if (dashboard.isPending) return html`Loading...`
+ if (dashboard.isError) return html`Unable to load dashboard`
+
+ return html`
+
Total projects: ${dashboard.projects.length}
+
Active users: ${dashboard.activeUsers}
+ `
+}
+```
+
+Having the same query key more than once in the `queries` array can cause those entries to share cached data. Deduplicate repeated keys first if each rendered row needs independent query state.
diff --git a/docs/framework/lit/guides/queries.md b/docs/framework/lit/guides/queries.md
new file mode 100644
index 00000000000..592cdcfd029
--- /dev/null
+++ b/docs/framework/lit/guides/queries.md
@@ -0,0 +1,141 @@
+---
+id: queries
+title: Queries
+---
+
+New to Lit Query? Start with [Installation](../installation.md) and [Quick Start](../quick-start.md) before wiring query controllers into your elements.
+
+## Query Basics
+
+A query is a declarative dependency on an asynchronous source of data tied to a unique key. Use queries for reading server state. If a function creates, updates, or deletes server data, use a [mutation](./mutations.md) instead.
+
+In Lit, subscribe to a query with [`createQueryController`](../reference/functions/createQueryController.md):
+
+```ts
+import { LitElement, html } from 'lit'
+import { createQueryController } from '@tanstack/lit-query'
+
+class TodosView extends LitElement {
+ private readonly todos = createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+ })
+
+ render() {
+ const query = this.todos()
+
+ if (query.isPending) return html`Loading...`
+ if (query.isError) return html`Error: ${query.error.message}`
+
+ return html`
+
+ ${query.data.map((todo) => html`
${todo.title}
`)}
+
+ `
+ }
+}
+```
+
+The controller needs:
+
+- A `ReactiveControllerHost`, usually `this` inside a `LitElement`
+- A unique `queryKey`
+- A `queryFn` that returns a promise and throws on errors
+
+The returned accessor exposes the current `QueryObserverResult`. Call it in `render`, or read `.current`:
+
+```ts
+const query = this.todos()
+const sameQuery = this.todos.current
+```
+
+## Query States
+
+A query can be in one primary state at a time:
+
+- `isPending` or `status === 'pending'`: no data is available yet
+- `isError` or `status === 'error'`: the query failed and `error` is available
+- `isSuccess` or `status === 'success'`: data is available
+
+The result also includes `isFetching`, which can be true during the initial load or a background refetch.
+
+```ts
+render() {
+ const query = this.todos()
+
+ if (query.status === 'pending') {
+ return html`Loading...`
+ }
+
+ if (query.status === 'error') {
+ return html`Error: ${query.error.message}`
+ }
+
+ return html``
+}
+```
+
+TypeScript will narrow `query.data` after you check `pending` and `error` before reading it.
+
+## Fetch Status
+
+The `status` field describes whether data is available. The `fetchStatus` field describes what the query function is doing:
+
+- `fetchStatus === 'fetching'`: the query is currently fetching.
+- `fetchStatus === 'paused'`: the query wanted to fetch, but fetching is paused.
+- `fetchStatus === 'idle'`: the query is not fetching.
+
+These states are intentionally separate. Background refetching and stale-while-revalidate behavior can produce combinations like:
+
+- A successful query with cached data can have `status === 'success'` and `fetchStatus === 'fetching'` while a background refetch is running.
+- A query with no data can have `status === 'pending'` and `fetchStatus === 'paused'` if fetching cannot start yet.
+
+Use `status` when deciding whether data can be rendered, and use `fetchStatus` or `isFetching` when deciding whether to show a network activity indicator:
+
+```ts
+render() {
+ const query = this.todos()
+
+ if (query.isPending) return html`Loading...`
+ if (query.isError) return html`Error: ${query.error.message}`
+
+ return html`
+ ${query.fetchStatus === 'fetching'
+ ? html`Refreshing...`
+ : null}
+
+ `
+}
+```
+
+## Reactive Query Options
+
+Use an options getter when the query key or query function depends on host state:
+
+```ts
+class UserTodos extends LitElement {
+ static properties = {
+ userId: { type: String },
+ }
+
+ userId = ''
+
+ private readonly todos = createQueryController(this, () => ({
+ queryKey: ['todos', this.userId],
+ queryFn: () => fetchTodos(this.userId),
+ enabled: this.userId.length > 0,
+ }))
+}
+```
+
+The query key is used for caching, refetching, and sharing data between controllers.
+
+## Refetching
+
+The accessor includes `refetch`:
+
+```ts
+html``
+```
+
+For multiple queries that should run at the same time, see [Parallel Queries](./parallel-queries.md).
diff --git a/docs/framework/lit/guides/query-functions.md b/docs/framework/lit/guides/query-functions.md
new file mode 100644
index 00000000000..74845737e82
--- /dev/null
+++ b/docs/framework/lit/guides/query-functions.md
@@ -0,0 +1,81 @@
+---
+id: query-functions
+title: Query Functions
+---
+
+A query function can be any function that returns a promise. The promise should resolve data or throw an error.
+
+```ts
+createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+})
+
+createQueryController(this, () => ({
+ queryKey: ['todo', this.todoId],
+ queryFn: () => fetchTodo(this.todoId),
+}))
+```
+
+## Handling Errors
+
+TanStack Query needs failed query functions to throw or return a rejected promise. Some clients do that automatically. The browser `fetch` API does not, so check `response.ok` yourself:
+
+```ts
+async function fetchTodos(): Promise {
+ const response = await fetch('/api/todos')
+
+ if (!response.ok) {
+ throw new Error('Failed to fetch todos')
+ }
+
+ return response.json() as Promise
+}
+```
+
+The thrown error is available on the query result:
+
+```ts
+const query = this.todos()
+
+if (query.isError) {
+ return html`Error: ${query.error.message}`
+}
+```
+
+## Query Function Context
+
+TanStack Query passes a context object to every query function. It includes:
+
+- `queryKey`: the current query key
+- `client`: the `QueryClient`
+- `signal`: an `AbortSignal` for cancellation
+- `meta`: optional query metadata
+
+```ts
+createQueryController(this, {
+ queryKey: ['todos', { status: 'open' }],
+ queryFn: async ({ queryKey, signal }) => {
+ const [, filters] = queryKey
+ const response = await fetch(`/api/todos?status=${filters.status}`, {
+ signal,
+ })
+ if (!response.ok) throw new Error('Failed to fetch todos')
+ return response.json() as Promise
+ },
+})
+```
+
+Infinite query functions also receive `pageParam`:
+
+```ts
+createInfiniteQueryController(this, {
+ queryKey: ['projects'],
+ queryFn: ({ pageParam }) => fetchProjectsPage(pageParam),
+ initialPageParam: 1,
+ getNextPageParam: (lastPage) =>
+ lastPage.hasMore ? lastPage.page + 1 : undefined,
+})
+```
+
+See [Infinite Queries](./infinite-queries.md) for the controller-specific behavior.
diff --git a/docs/framework/lit/guides/query-invalidation.md b/docs/framework/lit/guides/query-invalidation.md
new file mode 100644
index 00000000000..0227469ad41
--- /dev/null
+++ b/docs/framework/lit/guides/query-invalidation.md
@@ -0,0 +1,83 @@
+---
+id: query-invalidation
+title: Query Invalidation
+---
+
+Waiting for queries to become stale is not always enough. After a mutation succeeds, you often know that related cached data is out of date. Use `queryClient.invalidateQueries` to mark matching queries stale and refetch active observers.
+
+```ts
+queryClient.invalidateQueries()
+
+queryClient.invalidateQueries({
+ queryKey: ['todos'],
+})
+```
+
+When a query is invalidated:
+
+- It is marked stale, overriding any `staleTime`
+- If a matching query is active in a controller, it can refetch in the background
+
+## Invalidation from Mutations
+
+```ts
+private readonly addTodo = createMutationController(this, {
+ mutationFn: addTodo,
+ onSuccess: async () => {
+ await queryClient.invalidateQueries({ queryKey: ['todos'] })
+ },
+})
+```
+
+Use this pattern when the mutation result tells you related cached data is stale. The [Pagination example](../examples/pagination) shows invalidation after project mutations.
+
+## Query Matching
+
+Match a group of queries by prefix:
+
+```ts
+queryClient.invalidateQueries({ queryKey: ['projects'] })
+```
+
+Both of these query keys match:
+
+```ts
+const projectsListKey = ['projects']
+const projectsPageKey = ['projects', 1, 250, false]
+```
+
+Use a more specific key when only one slice should be invalidated:
+
+```ts
+queryClient.invalidateQueries({
+ queryKey: ['projects', this.page],
+})
+```
+
+Use `exact: true` to match only the exact key:
+
+```ts
+queryClient.invalidateQueries({
+ queryKey: ['projects'],
+ exact: true,
+})
+```
+
+## Manual Cache Updates
+
+Invalidation is usually simpler than normalized cache updates. When you do need immediate UI updates, combine targeted cache writes with invalidation:
+
+```ts
+queryClient.setQueryData(['todos'], (existing) => {
+ if (!existing) return existing
+
+ return {
+ ...existing,
+ items: [...existing.items, createdTodo],
+ }
+})
+
+await queryClient.invalidateQueries({ queryKey: ['todos'] })
+```
+
+For rollback with optimistic updates, see the mutation guide and the [Pagination example](../examples/pagination).
diff --git a/docs/framework/lit/guides/query-keys.md b/docs/framework/lit/guides/query-keys.md
new file mode 100644
index 00000000000..8a532e93e7e
--- /dev/null
+++ b/docs/framework/lit/guides/query-keys.md
@@ -0,0 +1,85 @@
+---
+id: query-keys
+title: Query Keys
+---
+
+TanStack Query manages caching by query key. Query keys must be arrays at the top level, and they should uniquely describe the data returned by the query function.
+
+## Simple Keys
+
+Use simple keys for list resources or non-hierarchical data:
+
+```ts
+createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+})
+
+createQueryController(this, {
+ queryKey: ['settings'],
+ queryFn: fetchSettings,
+})
+```
+
+## Keys with Variables
+
+Include variables when they change what the query fetches:
+
+```ts
+createQueryController(this, () => ({
+ queryKey: ['todo', this.todoId],
+ queryFn: () => fetchTodo(this.todoId),
+}))
+
+createQueryController(this, () => ({
+ queryKey: ['projects', { page: this.page, filter: this.filter }],
+ queryFn: () => fetchProjects({ page: this.page, filter: this.filter }),
+}))
+```
+
+The pagination example uses a key shaped like this:
+
+```ts
+type ProjectsQueryKey = readonly ['projects', number, number, boolean]
+
+function projectsQueryKey(
+ page: number,
+ delayMs: number,
+ forceError: boolean,
+): ProjectsQueryKey {
+ return ['projects', page, delayMs, forceError] as const
+}
+```
+
+## Deterministic Hashing
+
+Object key order does not matter inside a query key:
+
+```ts
+const keyA = ['todos', { status, page }]
+const keyB = ['todos', { page, status }]
+```
+
+Array item order does matter:
+
+```ts
+const keyA = ['todos', status, page]
+const keyB = ['todos', page, status]
+```
+
+## Query Keys as Dependencies
+
+If your query function reads a reactive host property, include that value in the query key:
+
+```ts
+class UserTodos extends LitElement {
+ userId = ''
+
+ private readonly todos = createQueryController(this, () => ({
+ queryKey: ['todos', this.userId],
+ queryFn: () => fetchTodos(this.userId),
+ }))
+}
+```
+
+This lets Lit Query cache each user's todos separately and refetch when the host state changes.
diff --git a/docs/framework/lit/guides/reactive-controllers-vs-hooks.md b/docs/framework/lit/guides/reactive-controllers-vs-hooks.md
new file mode 100644
index 00000000000..0cb0530ed0b
--- /dev/null
+++ b/docs/framework/lit/guides/reactive-controllers-vs-hooks.md
@@ -0,0 +1,111 @@
+---
+id: reactive-controllers-vs-hooks
+title: Reactive Controllers vs Hooks
+---
+
+React Query examples use hooks. Lit Query uses reactive controllers.
+
+The job is similar: subscribe a component to a `QueryClient`, read the latest result, and update the component when the cache changes. The integration point is different because Lit components use the `ReactiveControllerHost` interface instead of React's render and hook system.
+
+## Mapping the Concepts
+
+| React Query | Lit Query |
+| --------------------------- | ---------------------------------------------- |
+| `useQuery(options)` | `createQueryController(this, options)` |
+| `useQueries(options)` | `createQueriesController(this, options)` |
+| `useMutation(options)` | `createMutationController(this, options)` |
+| `useInfiniteQuery(options)` | `createInfiniteQueryController(this, options)` |
+| `useIsFetching(options)` | `useIsFetching(this, options)` |
+| `useIsMutating(options)` | `useIsMutating(this, options)` |
+| `useMutationState(options)` | `useMutationState(this, options)` |
+| Hook result object | Callable result accessor |
+| React context provider | `QueryClientProvider` custom element |
+| Component render rerun | `host.requestUpdate()` |
+
+## Host-Bound APIs
+
+Lit APIs that subscribe a component to query or mutation state receive a `host` as the first argument:
+
+```ts
+class TodosView extends LitElement {
+ private readonly todos = createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+ })
+}
+```
+
+`this` is valid because `LitElement` implements `ReactiveControllerHost`. The controller attaches to the host, subscribes when the host connects, requests updates when the query result changes, and unsubscribes when the host disconnects.
+
+The host-bound APIs are [`createQueryController`](../reference/functions/createQueryController.md), [`createQueriesController`](../reference/functions/createQueriesController.md), [`createInfiniteQueryController`](../reference/functions/createInfiniteQueryController.md), [`createMutationController`](../reference/functions/createMutationController.md), [`useIsFetching`](../reference/functions/useIsFetching.md), [`useIsMutating`](../reference/functions/useIsMutating.md), and [`useMutationState`](../reference/functions/useMutationState.md).
+
+[`useQueryClient`](../reference/functions/useQueryClient.md) is different. It is not a reactive controller, does not accept a host, does not subscribe, and throws synchronously if no single default client is available. Use it only for imperative code that runs while exactly one `QueryClientProvider` is connected. Inside host-bound APIs, prefer the provider context or pass an explicit `QueryClient`.
+
+## Reading Results
+
+Lit Query controller creators return a callable accessor with a `current` property:
+
+```ts
+const query = this.todos()
+const sameQuery = this.todos.current
+```
+
+Render methods normally call the accessor:
+
+```ts
+render() {
+ const query = this.todos()
+
+ if (query.isPending) return html`Loading...`
+ if (query.isError) return html`Error: ${query.error.message}`
+
+ return html``
+}
+```
+
+## Reactive Options
+
+If query options depend on host state, pass a function. Lit Query re-reads function accessors during host updates:
+
+```ts
+class ProjectView extends LitElement {
+ static properties = {
+ projectId: { type: Number },
+ }
+
+ projectId = 1
+
+ private readonly project = createQueryController(this, () => ({
+ queryKey: ['project', this.projectId],
+ queryFn: () => fetchProject(this.projectId),
+ }))
+}
+```
+
+If options are static, pass an object. If you mutate a static options object yourself, call the controller helper that causes the observer to see the new options, such as `refetch`, or prefer a function accessor for reactive state.
+
+## Provider Context
+
+Host-bound APIs can receive an explicit `QueryClient`, but most apps render under [`QueryClientProvider`](../reference/classes/QueryClientProvider.md). The provider uses Lit context to deliver the client to descendant controllers.
+
+```ts
+customElements.define('query-client-provider', QueryClientProvider)
+```
+
+```ts
+html`
+
+
+
+`
+```
+
+Custom element registration is always the application's responsibility.
+
+`QueryClientProvider` also registers its client in a process-local fallback store for [`useQueryClient`](../reference/functions/useQueryClient.md) and [`resolveQueryClient`](../reference/functions/resolveQueryClient.md). That fallback is intentionally conservative:
+
+- If no provider is connected, `useQueryClient()` throws.
+- If exactly one distinct client is connected, `useQueryClient()` returns it.
+- If multiple distinct clients are connected in the same JavaScript context, `useQueryClient()` and `resolveQueryClient()` throw because the fallback would be ambiguous.
+
+Multiple roots, micro-frontends, test suites with shared modules, and nested apps should avoid relying on the process-local fallback. Render host-bound controllers under the right provider, pass an explicit `QueryClient` to the controller, or cleanly disconnect providers between tests.
diff --git a/docs/framework/lit/guides/ssr.md b/docs/framework/lit/guides/ssr.md
new file mode 100644
index 00000000000..0c6cce2e476
--- /dev/null
+++ b/docs/framework/lit/guides/ssr.md
@@ -0,0 +1,145 @@
+---
+id: ssr
+title: Server Rendering & Hydration
+---
+
+Lit Query can be used with server rendering by combining Lit SSR with TanStack Query Core hydration APIs re-exported from `@tanstack/lit-query`.
+
+The runnable source for this guide is the [SSR example](../examples/ssr).
+
+## Flow
+
+Server rendering has three phases:
+
+1. Create a per-request `QueryClient`.
+2. Prefetch queries on the server and render Lit HTML with that client.
+3. Dehydrate the cache into the HTML, then hydrate a browser `QueryClient` before the client app renders.
+
+Never share one server `QueryClient` between users or requests.
+
+## Server Prefetch and Render
+
+```ts
+import { render } from '@lit-labs/ssr'
+import { collectResult } from '@lit-labs/ssr/lib/render-result.js'
+import { html } from 'lit'
+import { QueryClient, dehydrate } from '@tanstack/lit-query'
+import { createDataQueryOptions } from './api.js'
+import './app.js'
+
+async function renderPage() {
+ const apiBaseUrl = 'https://example.com'
+ const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ staleTime: 30_000,
+ },
+ },
+ })
+
+ await queryClient.prefetchQuery(createDataQueryOptions(apiBaseUrl))
+
+ const appHtml = await collectResult(
+ render(
+ html``,
+ ),
+ )
+
+ const dehydratedState = dehydrate(queryClient)
+
+ return { appHtml, dehydratedState }
+}
+```
+
+The server passes the same client into the Lit element with a property binding. This lets `createQueryController` read the prefetched cache during server render. If your query function calls `fetch` during SSR, pass an absolute API origin instead of relying on a browser-relative URL.
+
+## Client Hydration
+
+```ts
+import '@lit-labs/ssr-client/lit-element-hydrate-support.js'
+import { QueryClient, hydrate, type DehydratedState } from '@tanstack/lit-query'
+
+const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ staleTime: 30_000,
+ },
+ },
+})
+
+const dehydratedState = JSON.parse(
+ document.getElementById('__QUERY_STATE__')?.textContent ?? 'null',
+) as DehydratedState
+
+queryClient.mount()
+hydrate(queryClient, dehydratedState)
+
+const appElement = document.querySelector('ssr-app') as
+ | (HTMLElement & { queryClient?: QueryClient })
+ | null
+
+if (!appElement) {
+ throw new Error('Expected the SSR app element to exist before hydration.')
+}
+
+appElement.queryClient = queryClient
+await import('./app.js')
+```
+
+Unmount the client when the page is unloaded if you mounted it manually:
+
+```ts
+window.addEventListener(
+ 'pagehide',
+ () => {
+ queryClient.unmount()
+ },
+ { once: true },
+)
+```
+
+## Component Pattern
+
+The SSR example creates its controller only after a `queryClient` property is available:
+
+```ts
+import { LitElement } from 'lit'
+import {
+ createQueryController,
+ type QueryClient,
+ type QueryResultAccessor,
+} from '@tanstack/lit-query'
+import { createDataQueryOptions, type DataResponse } from './api.js'
+
+class SsrApp extends LitElement {
+ static properties = {
+ apiBaseUrl: { attribute: 'api-base-url' },
+ queryClient: { attribute: false },
+ }
+
+ apiBaseUrl = ''
+ queryClient?: QueryClient
+ private dataQuery?: QueryResultAccessor
+
+ protected override willUpdate(): void {
+ if (!this.dataQuery && this.queryClient) {
+ this.dataQuery = createQueryController(
+ this,
+ createDataQueryOptions(this.apiBaseUrl),
+ this.queryClient,
+ )
+ }
+ }
+}
+```
+
+This explicit-client pattern is useful for SSR because the client is created by the renderer rather than discovered from a connected DOM provider.
+
+## Serialization
+
+Embed dehydrated state as JSON in the HTML and escape characters that can break out of a script tag. The example server uses a small serializer before replacing `__QUERY_STATE_JSON__` in the built HTML template.
+
+Lit Query re-exports `dehydrate` and `hydrate` from TanStack Query Core. Use `dehydrate(queryClient)` after server prefetching to capture the cache state. In the browser, parse that state, create a fresh `QueryClient`, call `hydrate(queryClient, dehydratedState)`, assign the client to the server-rendered element, and only then import the Lit component so it upgrades with the prefetched cache available.
diff --git a/docs/framework/lit/installation.md b/docs/framework/lit/installation.md
new file mode 100644
index 00000000000..dacbadb9e58
--- /dev/null
+++ b/docs/framework/lit/installation.md
@@ -0,0 +1,109 @@
+---
+id: installation
+title: Installation
+---
+
+> IMPORTANT: The Lit adapter is currently experimental and v0.1. Pin exact versions if you need extra release stability while the API is early.
+
+Install Lit Query with Lit and TanStack Query Core:
+
+```bash
+npm i @tanstack/lit-query @tanstack/query-core lit
+```
+
+or
+
+```bash
+pnpm add @tanstack/lit-query @tanstack/query-core lit
+```
+
+or
+
+```bash
+yarn add @tanstack/lit-query @tanstack/query-core lit
+```
+
+or
+
+```bash
+bun add @tanstack/lit-query @tanstack/query-core lit
+```
+
+`@tanstack/query-core` is a peer dependency of `@tanstack/lit-query`. Even though the Lit docs import user-facing APIs from `@tanstack/lit-query`, your app should install `@tanstack/query-core` explicitly.
+
+## Requirements
+
+Lit Query is intended for Lit 2.8 and newer, including Lit 3. It uses Lit reactive controllers and Lit context, so query consumers should be `ReactiveControllerHost` instances such as `LitElement`.
+
+TanStack Query is optimized for modern browsers:
+
+```txt
+Chrome >= 91
+Firefox >= 90
+Edge >= 91
+Safari >= 15
+iOS >= 15
+Opera >= 77
+```
+
+## Provider Setup
+
+Create a `QueryClient`, provide it with `QueryClientProvider`, and register your custom element. The package exports the provider class but does not call `customElements.define` for you.
+
+### Subclass Pattern
+
+```ts
+import { QueryClient, QueryClientProvider } from '@tanstack/lit-query'
+
+const queryClient = new QueryClient()
+
+class AppQueryProvider extends QueryClientProvider {
+ constructor() {
+ super()
+ this.client = queryClient
+ }
+}
+
+customElements.define('app-query-provider', AppQueryProvider)
+```
+
+```html
+
+
+
+```
+
+### Direct Provider Element
+
+You can register the provider class directly and bind its `client` property from a Lit template. The dot is important: `.client=${queryClient}` is a property binding, not an HTML attribute.
+
+```ts
+import { LitElement, html } from 'lit'
+import { QueryClient, QueryClientProvider } from '@tanstack/lit-query'
+
+const queryClient = new QueryClient()
+
+customElements.define('query-client-provider', QueryClientProvider)
+
+class AppRoot extends LitElement {
+ render() {
+ return html`
+
+
+
+ `
+ }
+}
+```
+
+If a connected provider has no `client`, it throws. See the generated [`QueryClientProvider` reference](./reference/classes/QueryClientProvider.md) for the full contract.
+
+## Render Roots
+
+The snippets in these docs use Lit's default shadow DOM. Lit Query controllers and `QueryClientProvider` work with shadow DOM and light DOM because they use the host lifecycle and Lit context, not global selectors.
+
+Some runnable examples override `createRenderRoot()` and return `this` so their demo markup stays in light DOM for shared page styles and test selectors. That override is not required for Lit Query. Use light DOM only when your app has a separate reason to expose a component's internal markup to global CSS, tests, or non-shadow-DOM integration code.
+
+## Devtools Status
+
+Lit Devtools are not available yet. This is a current adapter limitation, not an installation step.
diff --git a/docs/framework/lit/overview.md b/docs/framework/lit/overview.md
new file mode 100644
index 00000000000..354848d6231
--- /dev/null
+++ b/docs/framework/lit/overview.md
@@ -0,0 +1,93 @@
+---
+id: overview
+title: Overview
+---
+
+> IMPORTANT: The `@tanstack/lit-query` package is currently experimental and v0.1. Expect the Lit adapter API and docs to keep evolving. If you use it in production while it is early, pin the package to a patch version and upgrade deliberately.
+
+The `@tanstack/lit-query` package is the Lit adapter for TanStack Query. It gives Lit applications reactive controller APIs for fetching, caching, synchronizing, and updating server state.
+
+TanStack Query manages server state: data that is owned by a remote system, fetched asynchronously, shared across screens, and potentially changed by someone else at any time. It handles caching, request deduplication, stale data, background refetching, mutations, invalidation, pagination, and garbage collection.
+
+Lit Query exposes those features through [Lit reactive controllers](https://lit.dev/docs/composition/controllers/). A Lit reactive controller is attached to a `ReactiveControllerHost`, usually a `LitElement`. Lit Query controllers subscribe to the `QueryClient`, request host updates when results change, and are cleaned up with the host lifecycle.
+
+## Core APIs
+
+Most Lit applications use these APIs:
+
+- [`QueryClientProvider`](./reference/classes/QueryClientProvider.md) to provide a `QueryClient` through Lit context
+- [`createQueryController`](./reference/functions/createQueryController.md) for queries
+- [`createQueriesController`](./reference/functions/createQueriesController.md) for dynamic parallel queries
+- [`createMutationController`](./reference/functions/createMutationController.md) for mutations
+- [`createInfiniteQueryController`](./reference/functions/createInfiniteQueryController.md) for infinite queries
+- [`useIsFetching`](./reference/functions/useIsFetching.md), [`useIsMutating`](./reference/functions/useIsMutating.md), and [`useMutationState`](./reference/functions/useMutationState.md) for cache state indicators
+
+The adapter also re-exports TanStack Query Core APIs from `@tanstack/lit-query`, so examples in the Lit docs use `@tanstack/lit-query` as the user-facing import path.
+
+## A First Query
+
+```ts
+import { LitElement, html } from 'lit'
+import {
+ QueryClient,
+ QueryClientProvider,
+ createQueryController,
+} from '@tanstack/lit-query'
+
+const queryClient = new QueryClient()
+
+class AppQueryProvider extends QueryClientProvider {
+ constructor() {
+ super()
+ this.client = queryClient
+ }
+}
+
+customElements.define('app-query-provider', AppQueryProvider)
+
+class RepoStats extends LitElement {
+ private readonly repo = createQueryController(this, {
+ queryKey: ['repoData'],
+ queryFn: async () => {
+ const response = await fetch(
+ 'https://api.github.com/repos/TanStack/query',
+ )
+ if (!response.ok) throw new Error('Failed to fetch repo data')
+ return response.json() as Promise<{
+ name: string
+ description: string
+ stargazers_count: number
+ }>
+ },
+ })
+
+ render() {
+ const query = this.repo()
+
+ if (query.isPending) return html`Loading...`
+ if (query.isError) return html`Error: ${query.error.message}`
+
+ return html`
+
${query.data.name}
+
${query.data.description}
+ ${query.data.stargazers_count} stars
+ `
+ }
+}
+
+customElements.define('repo-stats', RepoStats)
+```
+
+Render the provider above your query consumers:
+
+```html
+
+
+
+```
+
+## Status Notes
+
+Lit Devtools are not available yet. Use the cache APIs and the generated API reference while the adapter matures.
+
+Start with [Installation](./installation.md), then [Quick Start](./quick-start.md), and use the [Reactive Controllers vs Hooks](./guides/reactive-controllers-vs-hooks.md) guide if you are coming from React Query.
diff --git a/docs/framework/lit/quick-start.md b/docs/framework/lit/quick-start.md
new file mode 100644
index 00000000000..69bff6c8f11
--- /dev/null
+++ b/docs/framework/lit/quick-start.md
@@ -0,0 +1,83 @@
+---
+id: quick-start
+title: Quick Start
+---
+
+This snippet shows the three core Lit Query concepts:
+
+- [Queries](./guides/queries.md)
+- [Mutations](./guides/mutations.md)
+- [Query Invalidation](./guides/query-invalidation.md)
+
+For complete runnable examples, see [Basic](./examples/basic), [Pagination](./examples/pagination), and [SSR](./examples/ssr).
+
+```ts
+import { LitElement, html } from 'lit'
+import {
+ QueryClient,
+ QueryClientProvider,
+ createMutationController,
+ createQueryController,
+} from '@tanstack/lit-query'
+import { addTodo, getTodos } from './api'
+
+const queryClient = new QueryClient()
+
+class AppQueryProvider extends QueryClientProvider {
+ constructor() {
+ super()
+ this.client = queryClient
+ }
+}
+
+customElements.define('app-query-provider', AppQueryProvider)
+
+class TodosView extends LitElement {
+ private readonly todos = createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: getTodos,
+ })
+
+ private readonly createTodo = createMutationController(this, {
+ mutationFn: addTodo,
+ onSuccess: async () => {
+ await queryClient.invalidateQueries({ queryKey: ['todos'] })
+ },
+ })
+
+ render() {
+ const query = this.todos()
+ const mutation = this.createTodo()
+
+ if (query.isPending) return html`Loading...`
+ if (query.isError) return html`Error: ${query.error.message}`
+
+ return html`
+
+ ${query.data.map((todo) => html`
${todo.title}
`)}
+
+
+
+ `
+ }
+}
+
+customElements.define('todos-view', TodosView)
+```
+
+Mount the provider around your component:
+
+```html
+
+
+
+```
+
+The controllers are created with `this` because a `LitElement` is a `ReactiveControllerHost`. Lit Query uses the host lifecycle to subscribe, request updates, and clean up when the element disconnects.
+
+Continue with [Reactive Controllers vs Hooks](./guides/reactive-controllers-vs-hooks.md) if you know React Query, or go straight to [Queries](./guides/queries.md).
diff --git a/docs/framework/lit/reference/classes/QueryClientProvider.md b/docs/framework/lit/reference/classes/QueryClientProvider.md
new file mode 100644
index 00000000000..df14c2769bb
--- /dev/null
+++ b/docs/framework/lit/reference/classes/QueryClientProvider.md
@@ -0,0 +1,98 @@
+---
+id: QueryClientProvider
+title: QueryClientProvider
+---
+
+# Class: QueryClientProvider
+
+Defined in: [packages/lit-query/src/QueryClientProvider.ts:64](https://github.com/TanStack/query/blob/main/packages/lit-query/src/QueryClientProvider.ts#L64)
+
+Lit element that provides a `QueryClient` to descendant Lit Query
+controllers through Lit context.
+
+The `client` is a property, not an attribute. When rendering this element in
+a Lit template, bind it with property binding: `.client=${queryClient}`.
+The provider throws if it connects without a client, or if an already
+connected provider has its client cleared.
+
+This class is not registered as a custom element by the package. Applications
+must register either a subclass or the class itself with
+`customElements.define`.
+
+## Examples
+
+```ts
+import { html, LitElement } from 'lit'
+import { QueryClient, QueryClientProvider } from '@tanstack/lit-query'
+
+const queryClient = new QueryClient()
+
+class AppQueryProvider extends QueryClientProvider {
+ constructor() {
+ super()
+ this.client = queryClient
+ }
+}
+
+customElements.define('app-query-provider', AppQueryProvider)
+
+class AppRoot extends LitElement {
+ render() {
+ return html``
+ }
+}
+```
+
+```ts
+import { html } from 'lit'
+import { QueryClient, QueryClientProvider } from '@tanstack/lit-query'
+
+const queryClient = new QueryClient()
+
+customElements.define('query-client-provider', QueryClientProvider)
+
+const view = html`
+
+
+
+`
+```
+
+## Extends
+
+- `LitElement`
+
+## Constructors
+
+### Constructor
+
+```ts
+new QueryClientProvider(): QueryClientProvider;
+```
+
+Defined in: [packages/lit-query/src/QueryClientProvider.ts:82](https://github.com/TanStack/query/blob/main/packages/lit-query/src/QueryClientProvider.ts#L82)
+
+#### Returns
+
+`QueryClientProvider`
+
+#### Overrides
+
+```ts
+LitElement.constructor
+```
+
+## Properties
+
+### client
+
+```ts
+client: QueryClient;
+```
+
+Defined in: [packages/lit-query/src/QueryClientProvider.ts:76](https://github.com/TanStack/query/blob/main/packages/lit-query/src/QueryClientProvider.ts#L76)
+
+The `QueryClient` provided to descendant controllers and global fallback
+helpers while this provider is connected.
+
+Bind this as a property in Lit templates with `.client=${queryClient}`.
diff --git a/docs/framework/lit/reference/functions/createInfiniteQueryController.md b/docs/framework/lit/reference/functions/createInfiniteQueryController.md
new file mode 100644
index 00000000000..63bccc835af
--- /dev/null
+++ b/docs/framework/lit/reference/functions/createInfiniteQueryController.md
@@ -0,0 +1,104 @@
+---
+id: createInfiniteQueryController
+title: createInfiniteQueryController
+---
+
+# Function: createInfiniteQueryController()
+
+```ts
+function createInfiniteQueryController(
+ host,
+ options,
+queryClient?): InfiniteQueryResultAccessor;
+```
+
+Defined in: [packages/lit-query/src/createInfiniteQueryController.ts:364](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createInfiniteQueryController.ts#L364)
+
+Creates a Lit reactive controller that subscribes the host to an infinite
+query.
+
+The returned accessor is callable and also exposes `current`, `refetch`,
+`fetchNextPage`, `fetchPreviousPage`, and `destroy`. When `options` is a
+function, it is re-read during host updates so query keys and options can
+follow reactive host state.
+
+If `queryClient` is omitted, the controller resolves the client from the
+nearest connected `QueryClientProvider`.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `Error`
+
+### TData
+
+`TData` = `InfiniteData`\<`TQueryFnData`, `unknown`\>
+
+### TQueryKey
+
+`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
+
+### TPageParam
+
+`TPageParam` = `unknown`
+
+## Parameters
+
+### host
+
+`ReactiveControllerHost`
+
+The Lit reactive controller host that owns the infinite query
+subscription.
+
+### options
+
+[`Accessor`](../type-aliases/Accessor.md)\<[`CreateInfiniteQueryOptions`](../type-aliases/CreateInfiniteQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>\>
+
+Infinite query observer options, or a getter that returns
+options.
+
+### queryClient?
+
+`QueryClient`
+
+Optional explicit query client. Provide this for
+controllers that should not resolve a client from Lit context.
+
+## Returns
+
+[`InfiniteQueryResultAccessor`](../type-aliases/InfiniteQueryResultAccessor.md)\<`TData`, `TError`\>
+
+An accessor for the latest infinite query result with page helper
+methods.
+
+## Example
+
+```ts
+import { LitElement, html } from 'lit'
+import { createInfiniteQueryController } from '@tanstack/lit-query'
+
+class ProjectsView extends LitElement {
+ private readonly projects = createInfiniteQueryController(this, {
+ queryKey: ['projects'],
+ queryFn: ({ pageParam }) => fetchProjects(pageParam),
+ initialPageParam: 0,
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
+ })
+
+ render() {
+ const query = this.projects()
+
+ return html`
+
+ `
+ }
+}
+```
diff --git a/docs/framework/lit/reference/functions/createMutationController.md b/docs/framework/lit/reference/functions/createMutationController.md
new file mode 100644
index 00000000000..3c870e06fe2
--- /dev/null
+++ b/docs/framework/lit/reference/functions/createMutationController.md
@@ -0,0 +1,96 @@
+---
+id: createMutationController
+title: createMutationController
+---
+
+# Function: createMutationController()
+
+```ts
+function createMutationController(
+ host,
+ options,
+queryClient?): MutationResultAccessor;
+```
+
+Defined in: [packages/lit-query/src/createMutationController.ts:338](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createMutationController.ts#L338)
+
+Creates a Lit reactive controller that subscribes the host to a mutation.
+
+The returned accessor is callable and also exposes `current`, `mutate`,
+`mutateAsync`, `reset`, and `destroy`. When `options` is a function, it is
+re-read during host updates so mutation options can follow reactive host
+state.
+
+If `queryClient` is omitted, the controller resolves the client from the
+nearest connected `QueryClientProvider`.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = `Error`
+
+### TVariables
+
+`TVariables` = `void`
+
+### TOnMutateResult
+
+`TOnMutateResult` = `unknown`
+
+## Parameters
+
+### host
+
+`ReactiveControllerHost`
+
+The Lit reactive controller host that owns the mutation
+subscription.
+
+### options
+
+[`Accessor`](../type-aliases/Accessor.md)\<[`CreateMutationOptions`](../type-aliases/CreateMutationOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>\>
+
+Mutation observer options, or a getter that returns options.
+
+### queryClient?
+
+`QueryClient`
+
+Optional explicit query client. Provide this for
+controllers that should not resolve a client from Lit context.
+
+## Returns
+
+[`MutationResultAccessor`](../type-aliases/MutationResultAccessor.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
+
+An accessor for the latest mutation result with mutation helper
+methods.
+
+## Example
+
+```ts
+import { LitElement, html } from 'lit'
+import { createMutationController } from '@tanstack/lit-query'
+
+class AddTodoForm extends LitElement {
+ private readonly addTodo = createMutationController(this, {
+ mutationFn: (title: string) =>
+ fetch('/api/todos', { method: 'POST', body: JSON.stringify({ title }) }),
+ })
+
+ render() {
+ const mutation = this.addTodo()
+
+ return html`
+
+ `
+ }
+}
+```
diff --git a/docs/framework/lit/reference/functions/createQueriesController.md b/docs/framework/lit/reference/functions/createQueriesController.md
new file mode 100644
index 00000000000..db5e74399cb
--- /dev/null
+++ b/docs/framework/lit/reference/functions/createQueriesController.md
@@ -0,0 +1,90 @@
+---
+id: createQueriesController
+title: createQueriesController
+---
+
+# Function: createQueriesController()
+
+```ts
+function createQueriesController(
+ host,
+ options,
+queryClient?): QueriesResultAccessor;
+```
+
+Defined in: [packages/lit-query/src/createQueriesController.ts:615](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueriesController.ts#L615)
+
+Creates a Lit reactive controller that subscribes the host to multiple
+queries.
+
+The returned accessor is callable and also exposes `current` and `destroy`.
+When `options` or `options.queries` is a function, it is re-read during host
+updates so the query list can follow reactive host state.
+
+If `queryClient` is omitted, the controller resolves the client from the
+nearest connected `QueryClientProvider`.
+
+## Type Parameters
+
+### TQueryOptions
+
+`TQueryOptions` *extends* `any`[]
+
+### TCombinedResult
+
+`TCombinedResult` = `CreateQueriesResults`\<`TQueryOptions`\>
+
+## Parameters
+
+### host
+
+`ReactiveControllerHost`
+
+The Lit reactive controller host that owns the queries
+subscription.
+
+### options
+
+[`Accessor`](../type-aliases/Accessor.md)\<[`CreateQueriesControllerOptions`](../type-aliases/CreateQueriesControllerOptions.md)\<`TQueryOptions`, `TCombinedResult`\>\>
+
+Queries controller options, or a getter that returns options.
+
+### queryClient?
+
+`QueryClient`
+
+Optional explicit query client. Provide this for
+controllers that should not resolve a client from Lit context.
+
+## Returns
+
+[`QueriesResultAccessor`](../type-aliases/QueriesResultAccessor.md)\<`TCombinedResult`\>
+
+An accessor for the latest query results, or the value returned by
+`combine`.
+
+## Example
+
+```ts
+import { LitElement, html } from 'lit'
+import { createQueriesController } from '@tanstack/lit-query'
+
+class DashboardView extends LitElement {
+ private readonly dashboard = createQueriesController(this, {
+ queries: [
+ { queryKey: ['stats'], queryFn: fetchStats },
+ { queryKey: ['projects'], queryFn: fetchProjects },
+ ],
+ combine: ([stats, projects]) => ({
+ stats: stats.data,
+ projects: projects.data ?? [],
+ isPending: stats.isPending || projects.isPending,
+ }),
+ })
+
+ render() {
+ const dashboard = this.dashboard()
+ return html`
Projects: ${dashboard.projects.length}
`
+ }
+}
+```
diff --git a/docs/framework/lit/reference/functions/createQueryController.md b/docs/framework/lit/reference/functions/createQueryController.md
new file mode 100644
index 00000000000..11e52770bbd
--- /dev/null
+++ b/docs/framework/lit/reference/functions/createQueryController.md
@@ -0,0 +1,97 @@
+---
+id: createQueryController
+title: createQueryController
+---
+
+# Function: createQueryController()
+
+```ts
+function createQueryController(
+ host,
+ options,
+queryClient?): QueryResultAccessor;
+```
+
+Defined in: [packages/lit-query/src/createQueryController.ts:319](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueryController.ts#L319)
+
+Creates a Lit reactive controller that subscribes the host to a single query.
+
+The returned accessor is callable and also exposes `current`, `refetch`,
+`suspense`, and `destroy`. When `options` is a function, it is re-read during
+host updates so query keys and options can follow reactive host state.
+
+If `queryClient` is omitted, the controller resolves the client from the
+nearest connected `QueryClientProvider`.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `Error`
+
+### TData
+
+`TData` = `TQueryFnData`
+
+### TQueryData
+
+`TQueryData` = `TQueryFnData`
+
+### TQueryKey
+
+`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
+
+## Parameters
+
+### host
+
+`ReactiveControllerHost`
+
+The Lit reactive controller host that owns the query
+subscription.
+
+### options
+
+[`Accessor`](../type-aliases/Accessor.md)\<[`CreateQueryOptions`](../type-aliases/CreateQueryOptions.md)\<`TQueryFnData`, `TError`, `TData`, `TQueryData`, `TQueryKey`\>\>
+
+Query observer options, or a getter that returns options.
+
+### queryClient?
+
+`QueryClient`
+
+Optional explicit query client. Provide this for
+controllers that should not resolve a client from Lit context.
+
+## Returns
+
+[`QueryResultAccessor`](../type-aliases/QueryResultAccessor.md)\<`TData`, `TError`\>
+
+An accessor for the latest query result with query helper methods.
+
+## Example
+
+```ts
+import { LitElement, html } from 'lit'
+import { createQueryController } from '@tanstack/lit-query'
+
+class TodosView extends LitElement {
+ private readonly todos = createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: async () => fetch('/api/todos').then((r) => r.json()),
+ })
+
+ render() {
+ const query = this.todos()
+
+ if (query.isPending) return html`Loading...`
+ if (query.isError) return html`Error`
+
+ return html`
${query.data.map((todo) => html`
${todo.title}
`)}
`
+ }
+}
+```
diff --git a/docs/framework/lit/reference/functions/getDefaultQueryClient.md b/docs/framework/lit/reference/functions/getDefaultQueryClient.md
new file mode 100644
index 00000000000..4c9ff19db48
--- /dev/null
+++ b/docs/framework/lit/reference/functions/getDefaultQueryClient.md
@@ -0,0 +1,22 @@
+---
+id: getDefaultQueryClient
+title: getDefaultQueryClient
+---
+
+# Function: getDefaultQueryClient()
+
+```ts
+function getDefaultQueryClient(): QueryClient | undefined;
+```
+
+Defined in: [packages/lit-query/src/context.ts:72](https://github.com/TanStack/query/blob/main/packages/lit-query/src/context.ts#L72)
+
+Returns the registered default `QueryClient`, if exactly one default client is
+available.
+
+## Returns
+
+`QueryClient` \| `undefined`
+
+The default query client, or `undefined` when there is no registered
+client or more than one registered client.
diff --git a/docs/framework/lit/reference/functions/infiniteQueryOptions.md b/docs/framework/lit/reference/functions/infiniteQueryOptions.md
new file mode 100644
index 00000000000..3ac26702f12
--- /dev/null
+++ b/docs/framework/lit/reference/functions/infiniteQueryOptions.md
@@ -0,0 +1,63 @@
+---
+id: infiniteQueryOptions
+title: infiniteQueryOptions
+---
+
+# Function: infiniteQueryOptions()
+
+```ts
+function infiniteQueryOptions(options): InfiniteQueryObserverOptions;
+```
+
+Defined in: [packages/lit-query/src/infiniteQueryOptions.ts:26](https://github.com/TanStack/query/blob/main/packages/lit-query/src/infiniteQueryOptions.ts#L26)
+
+Preserves and types infinite query options for reuse across Lit Query APIs.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `Error`
+
+### TData
+
+`TData` = `InfiniteData`\<`TQueryFnData`, `unknown`\>
+
+### TQueryKey
+
+`TQueryKey` *extends* readonly `unknown`[] = readonly `unknown`[]
+
+### TPageParam
+
+`TPageParam` = `unknown`
+
+## Parameters
+
+### options
+
+`InfiniteQueryObserverOptions`\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
+
+Infinite query options to preserve.
+
+## Returns
+
+`InfiniteQueryObserverOptions`\<`TQueryFnData`, `TError`, `TData`, `TQueryKey`, `TPageParam`\>
+
+The same options object.
+
+## Example
+
+```ts
+import { infiniteQueryOptions } from '@tanstack/lit-query'
+
+const projectsOptions = infiniteQueryOptions({
+ queryKey: ['projects'],
+ queryFn: ({ pageParam }) => fetchProjects(pageParam),
+ initialPageParam: 0,
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
+})
+```
diff --git a/docs/framework/lit/reference/functions/mutationOptions.md b/docs/framework/lit/reference/functions/mutationOptions.md
new file mode 100644
index 00000000000..966fb849098
--- /dev/null
+++ b/docs/framework/lit/reference/functions/mutationOptions.md
@@ -0,0 +1,57 @@
+---
+id: mutationOptions
+title: mutationOptions
+---
+
+# Function: mutationOptions()
+
+```ts
+function mutationOptions(options): MutationObserverOptions;
+```
+
+Defined in: [packages/lit-query/src/mutationOptions.ts:22](https://github.com/TanStack/query/blob/main/packages/lit-query/src/mutationOptions.ts#L22)
+
+Preserves and types mutation options for reuse across Lit Query APIs.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = `Error`
+
+### TVariables
+
+`TVariables` = `void`
+
+### TOnMutateResult
+
+`TOnMutateResult` = `unknown`
+
+## Parameters
+
+### options
+
+`MutationObserverOptions`\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
+
+Mutation options to preserve.
+
+## Returns
+
+`MutationObserverOptions`\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
+
+The same options object.
+
+## Example
+
+```ts
+import { mutationOptions } from '@tanstack/lit-query'
+
+const addTodoOptions = mutationOptions({
+ mutationKey: ['add-todo'],
+ mutationFn: (title: string) => addTodo(title),
+})
+```
diff --git a/docs/framework/lit/reference/functions/queryOptions.md b/docs/framework/lit/reference/functions/queryOptions.md
new file mode 100644
index 00000000000..2c43233ca26
--- /dev/null
+++ b/docs/framework/lit/reference/functions/queryOptions.md
@@ -0,0 +1,147 @@
+---
+id: queryOptions
+title: queryOptions
+---
+
+# Function: queryOptions()
+
+## Call Signature
+
+```ts
+function queryOptions(options): Omit, "queryFn"> & object & object;
+```
+
+Defined in: [packages/lit-query/src/queryOptions.ts:94](https://github.com/TanStack/query/blob/main/packages/lit-query/src/queryOptions.ts#L94)
+
+Brands query options so the `queryKey` carries the query function data and
+error types across TanStack Query APIs.
+
+### 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`\>
+
+Query options to preserve and brand.
+
+### Returns
+
+`Omit`\<`QueryObserverOptions`\<`TQueryFnData`, `TError`, `TData`, `TQueryFnData`, `TQueryKey`, `never`\>, `"queryFn"`\> & `object` & `object`
+
+The same options object with a typed `queryKey`.
+
+### Example
+
+```ts
+import { queryOptions } from '@tanstack/lit-query'
+
+const todosOptions = queryOptions({
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+ initialData: [],
+})
+```
+
+## Call Signature
+
+```ts
+function queryOptions(options): OmitKeyof, "queryFn"> & object & object;
+```
+
+Defined in: [packages/lit-query/src/queryOptions.ts:112](https://github.com/TanStack/query/blob/main/packages/lit-query/src/queryOptions.ts#L112)
+
+Brands query options so the `queryKey` carries the query function data and
+error types across TanStack Query APIs.
+
+### 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`\>
+
+Query options to preserve and brand.
+
+### Returns
+
+`OmitKeyof`\<`QueryObserverOptions`\<`TQueryFnData`, `TError`, `TData`, `TQueryFnData`, `TQueryKey`, `never`\>, `"queryFn"`\> & `object` & `object`
+
+The same options object with a typed `queryKey`.
+
+## Call Signature
+
+```ts
+function queryOptions(options): QueryObserverOptions & object & object;
+```
+
+Defined in: [packages/lit-query/src/queryOptions.ts:130](https://github.com/TanStack/query/blob/main/packages/lit-query/src/queryOptions.ts#L130)
+
+Brands query options so the `queryKey` carries the query function data and
+error types across TanStack Query APIs.
+
+### 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`\>
+
+Query options to preserve and brand.
+
+### Returns
+
+`QueryObserverOptions`\<`TQueryFnData`, `TError`, `TData`, `TQueryFnData`, `TQueryKey`, `never`\> & `object` & `object`
+
+The same options object with a typed `queryKey`.
diff --git a/docs/framework/lit/reference/functions/registerDefaultQueryClient.md b/docs/framework/lit/reference/functions/registerDefaultQueryClient.md
new file mode 100644
index 00000000000..d3174f600ca
--- /dev/null
+++ b/docs/framework/lit/reference/functions/registerDefaultQueryClient.md
@@ -0,0 +1,30 @@
+---
+id: registerDefaultQueryClient
+title: registerDefaultQueryClient
+---
+
+# Function: registerDefaultQueryClient()
+
+```ts
+function registerDefaultQueryClient(client): void;
+```
+
+Defined in: [packages/lit-query/src/context.ts:32](https://github.com/TanStack/query/blob/main/packages/lit-query/src/context.ts#L32)
+
+Registers a `QueryClient` as a process-local fallback for APIs that resolve a
+client without an explicit argument.
+
+`QueryClientProvider` calls this automatically while it is connected. Prefer
+passing an explicit client or rendering under a provider when possible.
+
+## Parameters
+
+### client
+
+`QueryClient`
+
+The query client to register as the current default.
+
+## Returns
+
+`void`
diff --git a/docs/framework/lit/reference/functions/resolveQueryClient.md b/docs/framework/lit/reference/functions/resolveQueryClient.md
new file mode 100644
index 00000000000..cfb0ba226ac
--- /dev/null
+++ b/docs/framework/lit/reference/functions/resolveQueryClient.md
@@ -0,0 +1,29 @@
+---
+id: resolveQueryClient
+title: resolveQueryClient
+---
+
+# Function: resolveQueryClient()
+
+```ts
+function resolveQueryClient(explicit?): QueryClient;
+```
+
+Defined in: [packages/lit-query/src/context.ts:118](https://github.com/TanStack/query/blob/main/packages/lit-query/src/context.ts#L118)
+
+Resolves an explicit `QueryClient` or falls back to `useQueryClient`.
+
+## Parameters
+
+### explicit?
+
+`QueryClient`
+
+Optional client supplied by the caller.
+
+## Returns
+
+`QueryClient`
+
+The explicit client when provided, otherwise the current default
+client.
diff --git a/docs/framework/lit/reference/functions/unregisterDefaultQueryClient.md b/docs/framework/lit/reference/functions/unregisterDefaultQueryClient.md
new file mode 100644
index 00000000000..8c82f497c35
--- /dev/null
+++ b/docs/framework/lit/reference/functions/unregisterDefaultQueryClient.md
@@ -0,0 +1,29 @@
+---
+id: unregisterDefaultQueryClient
+title: unregisterDefaultQueryClient
+---
+
+# Function: unregisterDefaultQueryClient()
+
+```ts
+function unregisterDefaultQueryClient(client): void;
+```
+
+Defined in: [packages/lit-query/src/context.ts:45](https://github.com/TanStack/query/blob/main/packages/lit-query/src/context.ts#L45)
+
+Unregisters a client previously registered with
+`registerDefaultQueryClient`.
+
+`QueryClientProvider` calls this automatically when it disconnects.
+
+## Parameters
+
+### client
+
+`QueryClient`
+
+The query client registration to release.
+
+## Returns
+
+`void`
diff --git a/docs/framework/lit/reference/functions/useIsFetching.md b/docs/framework/lit/reference/functions/useIsFetching.md
new file mode 100644
index 00000000000..6cfd72bb4e5
--- /dev/null
+++ b/docs/framework/lit/reference/functions/useIsFetching.md
@@ -0,0 +1,67 @@
+---
+id: useIsFetching
+title: useIsFetching
+---
+
+# Function: useIsFetching()
+
+```ts
+function useIsFetching(
+ host,
+ filters,
+ queryClient?): IsFetchingAccessor;
+```
+
+Defined in: [packages/lit-query/src/useIsFetching.ts:147](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useIsFetching.ts#L147)
+
+Creates a Lit reactive controller that tracks how many matching queries are
+currently fetching.
+
+When `filters` is a function, it is re-read during host updates so the count
+can follow reactive host state. If `queryClient` is omitted, the controller
+resolves the client from the nearest connected `QueryClientProvider`.
+
+## Parameters
+
+### host
+
+`ReactiveControllerHost`
+
+The Lit reactive controller host that owns the cache
+subscription.
+
+### filters
+
+[`Accessor`](../type-aliases/Accessor.md)\<`QueryFilters`\\> = `{}`
+
+Query filters, or a getter that returns query filters.
+
+### queryClient?
+
+`QueryClient`
+
+Optional explicit query client. Provide this for
+controllers that should not resolve a client from Lit context.
+
+## Returns
+
+[`IsFetchingAccessor`](../type-aliases/IsFetchingAccessor.md)
+
+An accessor for the current number of matching fetching queries.
+
+## Example
+
+```ts
+import { LitElement, html } from 'lit'
+import { useIsFetching } from '@tanstack/lit-query'
+
+class TodosStatus extends LitElement {
+ private readonly todosFetching = useIsFetching(this, {
+ queryKey: ['todos'],
+ })
+
+ render() {
+ return html`${this.todosFetching()} active todo fetches`
+ }
+}
+```
diff --git a/docs/framework/lit/reference/functions/useIsMutating.md b/docs/framework/lit/reference/functions/useIsMutating.md
new file mode 100644
index 00000000000..1991ee25266
--- /dev/null
+++ b/docs/framework/lit/reference/functions/useIsMutating.md
@@ -0,0 +1,67 @@
+---
+id: useIsMutating
+title: useIsMutating
+---
+
+# Function: useIsMutating()
+
+```ts
+function useIsMutating(
+ host,
+ filters,
+ queryClient?): IsMutatingAccessor;
+```
+
+Defined in: [packages/lit-query/src/useIsMutating.ts:147](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useIsMutating.ts#L147)
+
+Creates a Lit reactive controller that tracks how many matching mutations are
+currently pending.
+
+When `filters` is a function, it is re-read during host updates so the count
+can follow reactive host state. If `queryClient` is omitted, the controller
+resolves the client from the nearest connected `QueryClientProvider`.
+
+## Parameters
+
+### host
+
+`ReactiveControllerHost`
+
+The Lit reactive controller host that owns the cache
+subscription.
+
+### filters
+
+[`Accessor`](../type-aliases/Accessor.md)\<`MutationFilters`\<`unknown`, `Error`, `unknown`, `unknown`\>\> = `{}`
+
+Mutation filters, or a getter that returns mutation filters.
+
+### queryClient?
+
+`QueryClient`
+
+Optional explicit query client. Provide this for
+controllers that should not resolve a client from Lit context.
+
+## Returns
+
+[`IsMutatingAccessor`](../type-aliases/IsMutatingAccessor.md)
+
+An accessor for the current number of matching pending mutations.
+
+## Example
+
+```ts
+import { LitElement, html } from 'lit'
+import { useIsMutating } from '@tanstack/lit-query'
+
+class MutationStatus extends LitElement {
+ private readonly savesPending = useIsMutating(this, {
+ mutationKey: ['save-project'],
+ })
+
+ render() {
+ return html`${this.savesPending()} saves pending`
+ }
+}
+```
diff --git a/docs/framework/lit/reference/functions/useMutationState.md b/docs/framework/lit/reference/functions/useMutationState.md
new file mode 100644
index 00000000000..f12f55d38b2
--- /dev/null
+++ b/docs/framework/lit/reference/functions/useMutationState.md
@@ -0,0 +1,75 @@
+---
+id: useMutationState
+title: useMutationState
+---
+
+# Function: useMutationState()
+
+```ts
+function useMutationState(
+ host,
+ options,
+queryClient?): MutationStateAccessor;
+```
+
+Defined in: [packages/lit-query/src/useMutationState.ts:187](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useMutationState.ts#L187)
+
+Creates a Lit reactive controller that selects state from matching mutations
+in the mutation cache.
+
+When `options.filters` is a function, it is re-read during host updates so
+the selection can follow reactive host state. If `queryClient` is omitted,
+the controller resolves the client from the nearest connected
+`QueryClientProvider`.
+
+## Type Parameters
+
+### TResult
+
+`TResult` = `MutationState`\<`unknown`, `unknown`, `unknown`, `unknown`\>
+
+## Parameters
+
+### host
+
+`ReactiveControllerHost`
+
+The Lit reactive controller host that owns the mutation cache
+subscription.
+
+### options
+
+[`MutationStateOptions`](../type-aliases/MutationStateOptions.md)\<`TResult`\> = `{}`
+
+Mutation state filters and optional selector.
+
+### queryClient?
+
+`QueryClient`
+
+Optional explicit query client. Provide this for
+controllers that should not resolve a client from Lit context.
+
+## Returns
+
+[`MutationStateAccessor`](../type-aliases/MutationStateAccessor.md)\<`TResult`\>
+
+An accessor for the selected mutation state array.
+
+## Example
+
+```ts
+import { LitElement, html } from 'lit'
+import { useMutationState } from '@tanstack/lit-query'
+
+class PendingUploads extends LitElement {
+ private readonly uploads = useMutationState(this, {
+ filters: { mutationKey: ['upload'], status: 'pending' },
+ select: (mutation) => mutation.state.variables as File,
+ })
+
+ render() {
+ return html`${this.uploads().length} uploads pending`
+ }
+}
+```
diff --git a/docs/framework/lit/reference/functions/useQueryClient.md b/docs/framework/lit/reference/functions/useQueryClient.md
new file mode 100644
index 00000000000..72db893d0d5
--- /dev/null
+++ b/docs/framework/lit/reference/functions/useQueryClient.md
@@ -0,0 +1,25 @@
+---
+id: useQueryClient
+title: useQueryClient
+---
+
+# Function: useQueryClient()
+
+```ts
+function useQueryClient(): QueryClient;
+```
+
+Defined in: [packages/lit-query/src/context.ts:98](https://github.com/TanStack/query/blob/main/packages/lit-query/src/context.ts#L98)
+
+Resolves the current default `QueryClient` registered by a connected
+`QueryClientProvider`.
+
+This helper is useful outside a Lit reactive controller when a single
+provider is mounted. It throws if no client is registered or if multiple
+clients are mounted and the default would be ambiguous.
+
+## Returns
+
+`QueryClient`
+
+The single registered query client.
diff --git a/docs/framework/lit/reference/index.md b/docs/framework/lit/reference/index.md
new file mode 100644
index 00000000000..77ef5851377
--- /dev/null
+++ b/docs/framework/lit/reference/index.md
@@ -0,0 +1,59 @@
+---
+id: "@tanstack/lit-query"
+title: "@tanstack/lit-query"
+---
+
+# @tanstack/lit-query
+
+## Classes
+
+- [QueryClientProvider](classes/QueryClientProvider.md)
+
+## Type Aliases
+
+- [Accessor](type-aliases/Accessor.md)
+- [CreateInfiniteQueryOptions](type-aliases/CreateInfiniteQueryOptions.md)
+- [CreateMutationOptions](type-aliases/CreateMutationOptions.md)
+- [CreateQueriesControllerOptions](type-aliases/CreateQueriesControllerOptions.md)
+- [CreateQueriesInput](type-aliases/CreateQueriesInput.md)
+- [CreateQueryOptions](type-aliases/CreateQueryOptions.md)
+- [DefinedInitialDataOptions](type-aliases/DefinedInitialDataOptions.md)
+- [InfiniteQueryControllerOptions](type-aliases/InfiniteQueryControllerOptions.md)
+- [InfiniteQueryResultAccessor](type-aliases/InfiniteQueryResultAccessor.md)
+- [IsFetchingAccessor](type-aliases/IsFetchingAccessor.md)
+- [IsMutatingAccessor](type-aliases/IsMutatingAccessor.md)
+- [MutationControllerOptions](type-aliases/MutationControllerOptions.md)
+- [MutationControllerResult](type-aliases/MutationControllerResult.md)
+- [MutationResultAccessor](type-aliases/MutationResultAccessor.md)
+- [MutationStateAccessor](type-aliases/MutationStateAccessor.md)
+- [MutationStateOptions](type-aliases/MutationStateOptions.md)
+- [QueriesControllerOptions](type-aliases/QueriesControllerOptions.md)
+- [QueriesResultAccessor](type-aliases/QueriesResultAccessor.md)
+- [QueryControllerOptions](type-aliases/QueryControllerOptions.md)
+- [QueryControllerResult](type-aliases/QueryControllerResult.md)
+- [QueryResultAccessor](type-aliases/QueryResultAccessor.md)
+- [UndefinedInitialDataOptions](type-aliases/UndefinedInitialDataOptions.md)
+- [UnusedSkipTokenOptions](type-aliases/UnusedSkipTokenOptions.md)
+- [ValueAccessor](type-aliases/ValueAccessor.md)
+
+## Variables
+
+- [queryClientContext](variables/queryClientContext.md)
+
+## Functions
+
+- [createInfiniteQueryController](functions/createInfiniteQueryController.md)
+- [createMutationController](functions/createMutationController.md)
+- [createQueriesController](functions/createQueriesController.md)
+- [createQueryController](functions/createQueryController.md)
+- [getDefaultQueryClient](functions/getDefaultQueryClient.md)
+- [infiniteQueryOptions](functions/infiniteQueryOptions.md)
+- [mutationOptions](functions/mutationOptions.md)
+- [queryOptions](functions/queryOptions.md)
+- [registerDefaultQueryClient](functions/registerDefaultQueryClient.md)
+- [resolveQueryClient](functions/resolveQueryClient.md)
+- [unregisterDefaultQueryClient](functions/unregisterDefaultQueryClient.md)
+- [useIsFetching](functions/useIsFetching.md)
+- [useIsMutating](functions/useIsMutating.md)
+- [useMutationState](functions/useMutationState.md)
+- [useQueryClient](functions/useQueryClient.md)
diff --git a/docs/framework/lit/reference/type-aliases/Accessor.md b/docs/framework/lit/reference/type-aliases/Accessor.md
new file mode 100644
index 00000000000..95d77dee47a
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/Accessor.md
@@ -0,0 +1,30 @@
+---
+id: Accessor
+title: Accessor
+---
+
+# Type Alias: Accessor\
+
+```ts
+type Accessor = T | () => T;
+```
+
+Defined in: [packages/lit-query/src/accessor.ts:13](https://github.com/TanStack/query/blob/main/packages/lit-query/src/accessor.ts#L13)
+
+A value that can be passed directly or read from a zero-argument getter.
+
+Lit Query APIs read function accessors during host updates, so the getter can
+depend on reactive host state.
+
+## Type Parameters
+
+### T
+
+`T`
+
+## Example
+
+```ts
+const staticKey: Accessor = ['todos']
+const reactiveKey: Accessor = () => ['todos', this.userId]
+```
diff --git a/docs/framework/lit/reference/type-aliases/CreateInfiniteQueryOptions.md b/docs/framework/lit/reference/type-aliases/CreateInfiniteQueryOptions.md
new file mode 100644
index 00000000000..ba09bb1126c
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/CreateInfiniteQueryOptions.md
@@ -0,0 +1,39 @@
+---
+id: CreateInfiniteQueryOptions
+title: CreateInfiniteQueryOptions
+---
+
+# Type Alias: CreateInfiniteQueryOptions\
+
+```ts
+type CreateInfiniteQueryOptions = InfiniteQueryObserverOptions;
+```
+
+Defined in: [packages/lit-query/src/createInfiniteQueryController.ts:27](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createInfiniteQueryController.ts#L27)
+
+Options accepted by `createInfiniteQueryController`.
+
+This is the Lit adapter shape for `InfiniteQueryObserverOptions`. Pass it
+directly or through an `Accessor` when the options depend on Lit host state.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TData
+
+`TData` = `InfiniteData`\<`TQueryFnData`\>
+
+### TQueryKey
+
+`TQueryKey` *extends* `QueryKey` = `QueryKey`
+
+### TPageParam
+
+`TPageParam` = `unknown`
diff --git a/docs/framework/lit/reference/type-aliases/CreateMutationOptions.md b/docs/framework/lit/reference/type-aliases/CreateMutationOptions.md
new file mode 100644
index 00000000000..94d611682b5
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/CreateMutationOptions.md
@@ -0,0 +1,35 @@
+---
+id: CreateMutationOptions
+title: CreateMutationOptions
+---
+
+# Type Alias: CreateMutationOptions\
+
+```ts
+type CreateMutationOptions = MutationObserverOptions;
+```
+
+Defined in: [packages/lit-query/src/createMutationController.ts:25](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createMutationController.ts#L25)
+
+Options accepted by `createMutationController`.
+
+This is the Lit adapter shape for `MutationObserverOptions`. Pass it directly
+or through an `Accessor` when the options depend on Lit host state.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TVariables
+
+`TVariables` = `void`
+
+### TOnMutateResult
+
+`TOnMutateResult` = `unknown`
diff --git a/docs/framework/lit/reference/type-aliases/CreateQueriesControllerOptions.md b/docs/framework/lit/reference/type-aliases/CreateQueriesControllerOptions.md
new file mode 100644
index 00000000000..1f69e15b84a
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/CreateQueriesControllerOptions.md
@@ -0,0 +1,64 @@
+---
+id: CreateQueriesControllerOptions
+title: CreateQueriesControllerOptions
+---
+
+# Type Alias: CreateQueriesControllerOptions\
+
+```ts
+type CreateQueriesControllerOptions = object;
+```
+
+Defined in: [packages/lit-query/src/createQueriesController.ts:194](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueriesController.ts#L194)
+
+Options accepted by `createQueriesController`.
+
+`queries` can be a static list or a getter that returns the current list.
+`combine` can reshape the array of query results into a single value for the
+returned accessor.
+
+## Type Parameters
+
+### TQueryOptions
+
+`TQueryOptions` *extends* `any`[] = `any`[]
+
+### TCombinedResult
+
+`TCombinedResult` = `CreateQueriesResults`\<`TQueryOptions`\>
+
+## Properties
+
+### combine()?
+
+```ts
+optional combine: (result) => TCombinedResult;
+```
+
+Defined in: [packages/lit-query/src/createQueriesController.ts:208](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueriesController.ts#L208)
+
+Optional function that combines the query result array into one value.
+
+#### Parameters
+
+##### result
+
+`CreateQueriesResults`\<`TQueryOptions`\>
+
+#### Returns
+
+`TCombinedResult`
+
+***
+
+### queries
+
+```ts
+queries: Accessor<
+ | readonly [...CreateQueriesOptions]
+| readonly [...{ [K in keyof TQueryOptions]: GetCreateQueriesInput }]>;
+```
+
+Defined in: [packages/lit-query/src/createQueriesController.ts:199](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueriesController.ts#L199)
+
+Query options to observe, or a getter that returns the current options.
diff --git a/docs/framework/lit/reference/type-aliases/CreateQueriesInput.md b/docs/framework/lit/reference/type-aliases/CreateQueriesInput.md
new file mode 100644
index 00000000000..0f698f79617
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/CreateQueriesInput.md
@@ -0,0 +1,35 @@
+---
+id: CreateQueriesInput
+title: CreateQueriesInput
+---
+
+# Type Alias: CreateQueriesInput\
+
+```ts
+type CreateQueriesInput = QueryObserverOptions;
+```
+
+Defined in: [packages/lit-query/src/createQueriesController.ts:30](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueriesController.ts#L30)
+
+Options for one query inside `createQueriesController`.
+
+This mirrors `QueryObserverOptions` and is used by the tuple inference that
+maps each input query to its corresponding result.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TData
+
+`TData` = `TQueryFnData`
+
+### TQueryKey
+
+`TQueryKey` *extends* `QueryKey` = `QueryKey`
diff --git a/docs/framework/lit/reference/type-aliases/CreateQueryOptions.md b/docs/framework/lit/reference/type-aliases/CreateQueryOptions.md
new file mode 100644
index 00000000000..a967e779ac8
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/CreateQueryOptions.md
@@ -0,0 +1,40 @@
+---
+id: CreateQueryOptions
+title: CreateQueryOptions
+---
+
+# Type Alias: CreateQueryOptions\
+
+```ts
+type CreateQueryOptions = QueryObserverOptions;
+```
+
+Defined in: [packages/lit-query/src/createQueryController.ts:27](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueryController.ts#L27)
+
+Options accepted by `createQueryController`.
+
+This is the Lit adapter shape for `QueryObserverOptions`. It can be passed
+directly to `createQueryController`, or wrapped in an `Accessor` when the
+options depend on Lit host state.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TData
+
+`TData` = `TQueryFnData`
+
+### TQueryData
+
+`TQueryData` = `TQueryFnData`
+
+### TQueryKey
+
+`TQueryKey` *extends* `QueryKey` = `QueryKey`
diff --git a/docs/framework/lit/reference/type-aliases/DefinedInitialDataOptions.md b/docs/framework/lit/reference/type-aliases/DefinedInitialDataOptions.md
new file mode 100644
index 00000000000..b369207dbb3
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/DefinedInitialDataOptions.md
@@ -0,0 +1,48 @@
+---
+id: DefinedInitialDataOptions
+title: DefinedInitialDataOptions
+---
+
+# Type Alias: DefinedInitialDataOptions\
+
+```ts
+type DefinedInitialDataOptions = Omit, "queryFn"> & object;
+```
+
+Defined in: [packages/lit-query/src/queryOptions.ts:16](https://github.com/TanStack/query/blob/main/packages/lit-query/src/queryOptions.ts#L16)
+
+Query options with `initialData` that guarantees defined query data.
+
+## 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`
diff --git a/docs/framework/lit/reference/type-aliases/InfiniteQueryControllerOptions.md b/docs/framework/lit/reference/type-aliases/InfiniteQueryControllerOptions.md
new file mode 100644
index 00000000000..f2b6bbe0b58
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/InfiniteQueryControllerOptions.md
@@ -0,0 +1,36 @@
+---
+id: InfiniteQueryControllerOptions
+title: InfiniteQueryControllerOptions
+---
+
+# Type Alias: InfiniteQueryControllerOptions\
+
+```ts
+type InfiniteQueryControllerOptions = Accessor>;
+```
+
+Defined in: [packages/lit-query/src/types.ts:41](https://github.com/TanStack/query/blob/main/packages/lit-query/src/types.ts#L41)
+
+Accessor-wrapped options accepted by `createInfiniteQueryController`.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TData
+
+`TData` = `InfiniteData`\<`TQueryFnData`\>
+
+### TQueryKey
+
+`TQueryKey` *extends* `QueryKey` = `QueryKey`
+
+### TPageParam
+
+`TPageParam` = `unknown`
diff --git a/docs/framework/lit/reference/type-aliases/InfiniteQueryResultAccessor.md b/docs/framework/lit/reference/type-aliases/InfiniteQueryResultAccessor.md
new file mode 100644
index 00000000000..a45900de25f
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/InfiniteQueryResultAccessor.md
@@ -0,0 +1,66 @@
+---
+id: InfiniteQueryResultAccessor
+title: InfiniteQueryResultAccessor
+---
+
+# Type Alias: InfiniteQueryResultAccessor\
+
+```ts
+type InfiniteQueryResultAccessor = ValueAccessor> & object;
+```
+
+Defined in: [packages/lit-query/src/createInfiniteQueryController.ts:48](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createInfiniteQueryController.ts#L48)
+
+Accessor returned by `createInfiniteQueryController`.
+
+Call the accessor or read its `current` property to get the latest infinite
+query result. The attached methods delegate to the active infinite query
+observer.
+
+## Type Declaration
+
+### destroy()
+
+```ts
+destroy: () => void;
+```
+
+Removes the controller from its Lit host and unsubscribes observers.
+
+#### Returns
+
+`void`
+
+### fetchNextPage
+
+```ts
+fetchNextPage: InfiniteQueryObserverResult["fetchNextPage"];
+```
+
+Fetches the next page for the current infinite query.
+
+### fetchPreviousPage
+
+```ts
+fetchPreviousPage: InfiniteQueryObserverResult["fetchPreviousPage"];
+```
+
+Fetches the previous page for the current infinite query.
+
+### refetch
+
+```ts
+refetch: InfiniteQueryObserverResult["refetch"];
+```
+
+Refetches the current infinite query.
+
+## Type Parameters
+
+### TData
+
+`TData`
+
+### TError
+
+`TError`
diff --git a/docs/framework/lit/reference/type-aliases/IsFetchingAccessor.md b/docs/framework/lit/reference/type-aliases/IsFetchingAccessor.md
new file mode 100644
index 00000000000..99c09c43502
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/IsFetchingAccessor.md
@@ -0,0 +1,29 @@
+---
+id: IsFetchingAccessor
+title: IsFetchingAccessor
+---
+
+# Type Alias: IsFetchingAccessor
+
+```ts
+type IsFetchingAccessor = ValueAccessor & object;
+```
+
+Defined in: [packages/lit-query/src/useIsFetching.ts:17](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useIsFetching.ts#L17)
+
+Accessor returned by `useIsFetching`.
+
+Call the accessor or read its `current` property to get the number of
+currently fetching queries that match the filters.
+
+## Type Declaration
+
+### destroy()
+
+```ts
+destroy: () => void;
+```
+
+#### Returns
+
+`void`
diff --git a/docs/framework/lit/reference/type-aliases/IsMutatingAccessor.md b/docs/framework/lit/reference/type-aliases/IsMutatingAccessor.md
new file mode 100644
index 00000000000..1f0ff1194f7
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/IsMutatingAccessor.md
@@ -0,0 +1,29 @@
+---
+id: IsMutatingAccessor
+title: IsMutatingAccessor
+---
+
+# Type Alias: IsMutatingAccessor
+
+```ts
+type IsMutatingAccessor = ValueAccessor & object;
+```
+
+Defined in: [packages/lit-query/src/useIsMutating.ts:17](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useIsMutating.ts#L17)
+
+Accessor returned by `useIsMutating`.
+
+Call the accessor or read its `current` property to get the number of
+currently pending mutations that match the filters.
+
+## Type Declaration
+
+### destroy()
+
+```ts
+destroy: () => void;
+```
+
+#### Returns
+
+`void`
diff --git a/docs/framework/lit/reference/type-aliases/MutationControllerOptions.md b/docs/framework/lit/reference/type-aliases/MutationControllerOptions.md
new file mode 100644
index 00000000000..6482d82a13a
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/MutationControllerOptions.md
@@ -0,0 +1,32 @@
+---
+id: MutationControllerOptions
+title: MutationControllerOptions
+---
+
+# Type Alias: MutationControllerOptions\
+
+```ts
+type MutationControllerOptions = Accessor>;
+```
+
+Defined in: [packages/lit-query/src/types.ts:54](https://github.com/TanStack/query/blob/main/packages/lit-query/src/types.ts#L54)
+
+Accessor-wrapped options accepted by `createMutationController`.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TVariables
+
+`TVariables` = `void`
+
+### TOnMutateResult
+
+`TOnMutateResult` = `unknown`
diff --git a/docs/framework/lit/reference/type-aliases/MutationControllerResult.md b/docs/framework/lit/reference/type-aliases/MutationControllerResult.md
new file mode 100644
index 00000000000..8b63b098fba
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/MutationControllerResult.md
@@ -0,0 +1,32 @@
+---
+id: MutationControllerResult
+title: MutationControllerResult
+---
+
+# Type Alias: MutationControllerResult\
+
+```ts
+type MutationControllerResult = MutationObserverResult;
+```
+
+Defined in: [packages/lit-query/src/types.ts:64](https://github.com/TanStack/query/blob/main/packages/lit-query/src/types.ts#L64)
+
+Result object produced by a Lit mutation controller.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TVariables
+
+`TVariables` = `void`
+
+### TOnMutateResult
+
+`TOnMutateResult` = `unknown`
diff --git a/docs/framework/lit/reference/type-aliases/MutationResultAccessor.md b/docs/framework/lit/reference/type-aliases/MutationResultAccessor.md
new file mode 100644
index 00000000000..6846aec42aa
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/MutationResultAccessor.md
@@ -0,0 +1,91 @@
+---
+id: MutationResultAccessor
+title: MutationResultAccessor
+---
+
+# Type Alias: MutationResultAccessor\
+
+```ts
+type MutationResultAccessor = ValueAccessor> & object;
+```
+
+Defined in: [packages/lit-query/src/createMutationController.ts:38](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createMutationController.ts#L38)
+
+Accessor returned by `createMutationController`.
+
+Call the accessor or read its `current` property to get the latest mutation
+result. The attached methods delegate to the active mutation observer.
+
+## Type Declaration
+
+### destroy()
+
+```ts
+destroy: () => void;
+```
+
+Removes the controller from its Lit host and unsubscribes observers.
+
+#### Returns
+
+`void`
+
+### mutate()
+
+```ts
+mutate: (variables, options?) => void;
+```
+
+Starts the mutation and swallows the returned promise.
+
+Throws synchronously if no `QueryClient` can be resolved.
+
+#### Parameters
+
+##### variables
+
+`TVariables`
+
+##### options?
+
+`MutateOptions`\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
+
+#### Returns
+
+`void`
+
+### mutateAsync
+
+```ts
+mutateAsync: MutationObserverResult["mutate"];
+```
+
+Starts the mutation and returns the observer promise.
+
+Rejects if no `QueryClient` can be resolved.
+
+### reset
+
+```ts
+reset: MutationObserverResult["reset"];
+```
+
+Resets the mutation observer to its idle state.
+
+## Type Parameters
+
+### TData
+
+`TData`
+
+### TError
+
+`TError`
+
+### TVariables
+
+`TVariables`
+
+### TOnMutateResult
+
+`TOnMutateResult`
diff --git a/docs/framework/lit/reference/type-aliases/MutationStateAccessor.md b/docs/framework/lit/reference/type-aliases/MutationStateAccessor.md
new file mode 100644
index 00000000000..6c9f9298caa
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/MutationStateAccessor.md
@@ -0,0 +1,37 @@
+---
+id: MutationStateAccessor
+title: MutationStateAccessor
+---
+
+# Type Alias: MutationStateAccessor\
+
+```ts
+type MutationStateAccessor = ValueAccessor & object;
+```
+
+Defined in: [packages/lit-query/src/useMutationState.ts:32](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useMutationState.ts#L32)
+
+Accessor returned by `useMutationState`.
+
+Call the accessor or read its `current` property to get the selected state for
+matching mutations.
+
+## Type Declaration
+
+### destroy()
+
+```ts
+destroy: () => void;
+```
+
+Removes the controller from its Lit host and unsubscribes observers.
+
+#### Returns
+
+`void`
+
+## Type Parameters
+
+### TResult
+
+`TResult`
diff --git a/docs/framework/lit/reference/type-aliases/MutationStateOptions.md b/docs/framework/lit/reference/type-aliases/MutationStateOptions.md
new file mode 100644
index 00000000000..7ae3228ea66
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/MutationStateOptions.md
@@ -0,0 +1,54 @@
+---
+id: MutationStateOptions
+title: MutationStateOptions
+---
+
+# Type Alias: MutationStateOptions\
+
+```ts
+type MutationStateOptions = object;
+```
+
+Defined in: [packages/lit-query/src/useMutationState.ts:19](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useMutationState.ts#L19)
+
+Options accepted by `useMutationState`.
+
+## Type Parameters
+
+### TResult
+
+`TResult`
+
+## Properties
+
+### filters?
+
+```ts
+optional filters: Accessor;
+```
+
+Defined in: [packages/lit-query/src/useMutationState.ts:21](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useMutationState.ts#L21)
+
+Filters used to select mutations from the mutation cache.
+
+***
+
+### select()?
+
+```ts
+optional select: (mutation) => TResult;
+```
+
+Defined in: [packages/lit-query/src/useMutationState.ts:23](https://github.com/TanStack/query/blob/main/packages/lit-query/src/useMutationState.ts#L23)
+
+Maps each matching mutation to the value returned by the accessor.
+
+#### Parameters
+
+##### mutation
+
+`Mutation`
+
+#### Returns
+
+`TResult`
diff --git a/docs/framework/lit/reference/type-aliases/QueriesControllerOptions.md b/docs/framework/lit/reference/type-aliases/QueriesControllerOptions.md
new file mode 100644
index 00000000000..70ef5a77f2b
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/QueriesControllerOptions.md
@@ -0,0 +1,24 @@
+---
+id: QueriesControllerOptions
+title: QueriesControllerOptions
+---
+
+# Type Alias: QueriesControllerOptions\
+
+```ts
+type QueriesControllerOptions = Accessor>;
+```
+
+Defined in: [packages/lit-query/src/types.ts:74](https://github.com/TanStack/query/blob/main/packages/lit-query/src/types.ts#L74)
+
+Accessor-wrapped options accepted by `createQueriesController`.
+
+## Type Parameters
+
+### TQueryOptions
+
+`TQueryOptions` *extends* `any`[] = `any`[]
+
+### TCombinedResult
+
+`TCombinedResult` = `CreateQueriesResults`\<`TQueryOptions`\>
diff --git a/docs/framework/lit/reference/type-aliases/QueriesResultAccessor.md b/docs/framework/lit/reference/type-aliases/QueriesResultAccessor.md
new file mode 100644
index 00000000000..c780231ee2f
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/QueriesResultAccessor.md
@@ -0,0 +1,37 @@
+---
+id: QueriesResultAccessor
+title: QueriesResultAccessor
+---
+
+# Type Alias: QueriesResultAccessor\
+
+```ts
+type QueriesResultAccessor = ValueAccessor & object;
+```
+
+Defined in: [packages/lit-query/src/createQueriesController.ts:217](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueriesController.ts#L217)
+
+Accessor returned by `createQueriesController`.
+
+Call the accessor or read its `current` property to get the latest combined
+value.
+
+## Type Declaration
+
+### destroy()
+
+```ts
+destroy: () => void;
+```
+
+Removes the controller from its Lit host and unsubscribes observers.
+
+#### Returns
+
+`void`
+
+## Type Parameters
+
+### TCombinedResult
+
+`TCombinedResult`
diff --git a/docs/framework/lit/reference/type-aliases/QueryControllerOptions.md b/docs/framework/lit/reference/type-aliases/QueryControllerOptions.md
new file mode 100644
index 00000000000..104d98c5fb9
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/QueryControllerOptions.md
@@ -0,0 +1,36 @@
+---
+id: QueryControllerOptions
+title: QueryControllerOptions
+---
+
+# Type Alias: QueryControllerOptions\
+
+```ts
+type QueryControllerOptions = Accessor>;
+```
+
+Defined in: [packages/lit-query/src/types.ts:20](https://github.com/TanStack/query/blob/main/packages/lit-query/src/types.ts#L20)
+
+Accessor-wrapped options accepted by `createQueryController`.
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TData
+
+`TData` = `TQueryFnData`
+
+### TQueryData
+
+`TQueryData` = `TQueryFnData`
+
+### TQueryKey
+
+`TQueryKey` *extends* `QueryKey` = `QueryKey`
diff --git a/docs/framework/lit/reference/type-aliases/QueryControllerResult.md b/docs/framework/lit/reference/type-aliases/QueryControllerResult.md
new file mode 100644
index 00000000000..853212d0536
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/QueryControllerResult.md
@@ -0,0 +1,24 @@
+---
+id: QueryControllerResult
+title: QueryControllerResult
+---
+
+# Type Alias: QueryControllerResult\
+
+```ts
+type QueryControllerResult = QueryObserverResult;
+```
+
+Defined in: [packages/lit-query/src/types.ts:33](https://github.com/TanStack/query/blob/main/packages/lit-query/src/types.ts#L33)
+
+Result object produced by a Lit query controller.
+
+## Type Parameters
+
+### TData
+
+`TData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
diff --git a/docs/framework/lit/reference/type-aliases/QueryResultAccessor.md b/docs/framework/lit/reference/type-aliases/QueryResultAccessor.md
new file mode 100644
index 00000000000..ce806098556
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/QueryResultAccessor.md
@@ -0,0 +1,61 @@
+---
+id: QueryResultAccessor
+title: QueryResultAccessor
+---
+
+# Type Alias: QueryResultAccessor\
+
+```ts
+type QueryResultAccessor = ValueAccessor> & object;
+```
+
+Defined in: [packages/lit-query/src/createQueryController.ts:41](https://github.com/TanStack/query/blob/main/packages/lit-query/src/createQueryController.ts#L41)
+
+Accessor returned by `createQueryController`.
+
+Call the accessor or read its `current` property to get the latest query
+result. The attached methods delegate to the active query observer.
+
+## Type Declaration
+
+### destroy()
+
+```ts
+destroy: () => void;
+```
+
+Removes the controller from its Lit host and unsubscribes observers.
+
+#### Returns
+
+`void`
+
+### refetch
+
+```ts
+refetch: QueryObserverResult["refetch"];
+```
+
+Refetches the current query.
+
+### suspense()
+
+```ts
+suspense: () => Promise>;
+```
+
+Resolves with an optimistic query result, fetching first when needed.
+
+#### Returns
+
+`Promise`\<`QueryObserverResult`\<`TData`, `TError`\>\>
+
+## Type Parameters
+
+### TData
+
+`TData`
+
+### TError
+
+`TError`
diff --git a/docs/framework/lit/reference/type-aliases/UndefinedInitialDataOptions.md b/docs/framework/lit/reference/type-aliases/UndefinedInitialDataOptions.md
new file mode 100644
index 00000000000..75aa69f4139
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/UndefinedInitialDataOptions.md
@@ -0,0 +1,42 @@
+---
+id: UndefinedInitialDataOptions
+title: UndefinedInitialDataOptions
+---
+
+# Type Alias: UndefinedInitialDataOptions\
+
+```ts
+type UndefinedInitialDataOptions = QueryObserverOptions & object;
+```
+
+Defined in: [packages/lit-query/src/queryOptions.ts:58](https://github.com/TanStack/query/blob/main/packages/lit-query/src/queryOptions.ts#L58)
+
+Query options where `initialData` can be omitted or undefined.
+
+## Type Declaration
+
+### initialData?
+
+```ts
+optional initialData:
+ | InitialDataFunction>
+| NonUndefinedGuard;
+```
+
+## Type Parameters
+
+### TQueryFnData
+
+`TQueryFnData` = `unknown`
+
+### TError
+
+`TError` = `DefaultError`
+
+### TData
+
+`TData` = `TQueryFnData`
+
+### TQueryKey
+
+`TQueryKey` *extends* `QueryKey` = `QueryKey`
diff --git a/docs/framework/lit/reference/type-aliases/UnusedSkipTokenOptions.md b/docs/framework/lit/reference/type-aliases/UnusedSkipTokenOptions.md
new file mode 100644
index 00000000000..53acb8d9f5c
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/UnusedSkipTokenOptions.md
@@ -0,0 +1,40 @@
+---
+id: UnusedSkipTokenOptions
+title: UnusedSkipTokenOptions
+---
+
+# Type Alias: UnusedSkipTokenOptions\
+
+```ts
+type UnusedSkipTokenOptions = OmitKeyof, "queryFn"> & object;
+```
+
+Defined in: [packages/lit-query/src/queryOptions.ts:34](https://github.com/TanStack/query/blob/main/packages/lit-query/src/queryOptions.ts#L34)
+
+Query options where `queryFn` is present and not a `skipToken`.
+
+## 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`
diff --git a/docs/framework/lit/reference/type-aliases/ValueAccessor.md b/docs/framework/lit/reference/type-aliases/ValueAccessor.md
new file mode 100644
index 00000000000..642c42f37da
--- /dev/null
+++ b/docs/framework/lit/reference/type-aliases/ValueAccessor.md
@@ -0,0 +1,39 @@
+---
+id: ValueAccessor
+title: ValueAccessor
+---
+
+# Type Alias: ValueAccessor\
+
+```ts
+type ValueAccessor = () => T & object;
+```
+
+Defined in: [packages/lit-query/src/accessor.ts:32](https://github.com/TanStack/query/blob/main/packages/lit-query/src/accessor.ts#L32)
+
+A callable accessor with a `current` property for reading the latest
+controller result.
+
+Controller creators and cache state helpers return this shape so render code
+can use either `result()` or `result.current`.
+
+## Type Declaration
+
+### current
+
+```ts
+readonly current: T;
+```
+
+## Type Parameters
+
+### T
+
+`T`
+
+## Example
+
+```ts
+const query = this.todos()
+const sameQuery = this.todos.current
+```
diff --git a/docs/framework/lit/reference/variables/queryClientContext.md b/docs/framework/lit/reference/variables/queryClientContext.md
new file mode 100644
index 00000000000..56395991d49
--- /dev/null
+++ b/docs/framework/lit/reference/variables/queryClientContext.md
@@ -0,0 +1,18 @@
+---
+id: queryClientContext
+title: queryClientContext
+---
+
+# Variable: queryClientContext
+
+```ts
+const queryClientContext: object;
+```
+
+Defined in: [packages/lit-query/src/context.ts:11](https://github.com/TanStack/query/blob/main/packages/lit-query/src/context.ts#L11)
+
+Lit context key used by `QueryClientProvider` and host-bound APIs to share a
+`QueryClient` through the DOM tree.
+
+Most applications use `QueryClientProvider` instead of interacting with this
+context directly.
diff --git a/docs/framework/lit/typescript.md b/docs/framework/lit/typescript.md
new file mode 100644
index 00000000000..6a59b09b1d7
--- /dev/null
+++ b/docs/framework/lit/typescript.md
@@ -0,0 +1,132 @@
+---
+id: typescript
+title: TypeScript
+---
+
+Lit Query is written in TypeScript and reuses TanStack Query Core's type system. The most important rule is the same as every other adapter: give your query and mutation functions well-defined return types, and the result accessors will infer from them.
+
+## Query Inference
+
+```ts
+import { LitElement } from 'lit'
+import { createQueryController } from '@tanstack/lit-query'
+
+type Todo = {
+ id: number
+ title: string
+}
+
+async function fetchTodos(): Promise {
+ const response = await fetch('/api/todos')
+ if (!response.ok) throw new Error('Failed to fetch todos')
+ return response.json() as Promise
+}
+
+class TodosView extends LitElement {
+ private readonly todos = createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+ })
+
+ render() {
+ const query = this.todos()
+ // query.data is Todo[] | undefined until success is known.
+ }
+}
+```
+
+Checking `isSuccess`, `isPending`, `isError`, or `status` narrows the result just like TanStack Query Core result types:
+
+```ts
+const query = this.todos()
+
+if (query.isSuccess) {
+ query.data
+ // Todo[]
+}
+```
+
+## Mutation Inference
+
+```ts
+import { LitElement } from 'lit'
+import { createMutationController } from '@tanstack/lit-query'
+
+type CreateTodoInput = {
+ title: string
+}
+
+type Todo = {
+ id: number
+ title: string
+}
+
+async function addTodo(input: CreateTodoInput): Promise {
+ const response = await fetch('/api/todos', {
+ method: 'POST',
+ body: JSON.stringify(input),
+ })
+ if (!response.ok) throw new Error('Failed to create todo')
+ return response.json() as Promise
+}
+
+class AddTodoButton extends LitElement {
+ private readonly mutation = createMutationController(this, {
+ mutationFn: addTodo,
+ })
+
+ private add() {
+ this.mutation.mutate({ title: 'Learn Lit Query' })
+ }
+}
+```
+
+## Extracting Options
+
+Use [`queryOptions`](./reference/functions/queryOptions.md), [`infiniteQueryOptions`](./reference/functions/infiniteQueryOptions.md), and [`mutationOptions`](./reference/functions/mutationOptions.md) when you want to share typed options between controllers and `QueryClient` calls.
+
+```ts
+import { LitElement } from 'lit'
+import {
+ QueryClient,
+ createQueryController,
+ queryOptions,
+} from '@tanstack/lit-query'
+
+function todosOptions() {
+ return queryOptions({
+ queryKey: ['todos'],
+ queryFn: fetchTodos,
+ staleTime: 5_000,
+ })
+}
+
+const queryClient = new QueryClient()
+
+class TodosView extends LitElement {
+ private readonly todos = createQueryController(this, todosOptions())
+}
+
+void queryClient.prefetchQuery(todosOptions())
+```
+
+The branded `queryKey` returned from `queryOptions` also helps APIs like `queryClient.getQueryData` understand the data type.
+
+## Global Register Types
+
+Because `@tanstack/lit-query` re-exports TanStack Query Core, module augmentation is written against `@tanstack/lit-query` in Lit apps:
+
+```ts
+import '@tanstack/lit-query'
+
+type AppQueryKey = ['todos' | 'projects', ...ReadonlyArray]
+
+declare module '@tanstack/lit-query' {
+ interface Register {
+ queryKey: AppQueryKey
+ mutationKey: AppQueryKey
+ }
+}
+```
+
+See the generated reference for Lit-specific [option and result types](./reference/index.md).
diff --git a/docs/framework/preact/devtools.md b/docs/framework/preact/devtools.md
index 4ea851d0fa6..4fc60265dc4 100644
--- a/docs/framework/preact/devtools.md
+++ b/docs/framework/preact/devtools.md
@@ -70,18 +70,68 @@ function App() {
- `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"`
+- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "relative"`
- Defaults to `bottom-right`
- - The position of the Preact Query logo to open and close the devtools panel
+ - The position of the TanStack 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}`
+- `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.
+- `theme?: "light" | "dark" | "system"`
+ - Defaults to `system`.
+ - Set this to change the theme of the devtools panel.
+
+## Embedded Mode
+
+Embedded mode will show the development tools as a fixed element in your application, so you can use our panel in your own development tools.
+
+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 { useState } from 'preact/hooks'
+import { PreactQueryDevtoolsPanel } from '@tanstack/preact-query-devtools'
+
+function App() {
+ const [isOpen, setIsOpen] = useState(false)
+
+ return (
+
+ {/* The rest of your application */}
+
+ {isOpen && setIsOpen(false)} />}
+
+ )
+}
+```
+
+### Options
+
+- `style?: CSSProperties`
+ - Custom styles for the devtools panel
+ - Default: `{ height: '500px' }`
+ - Example: `{ height: '100%' }`
+ - Example: `{ height: '100%', width: '100%' }`
+- `onClose?: () => void`
+ - Callback function that is called when the devtools panel is closed
+- `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.
+- `theme?: "light" | "dark" | "system"`
+ - Defaults to `system`.
+ - Set this to change the theme of the devtools panel.
diff --git a/docs/framework/react/devtools.md b/docs/framework/react/devtools.md
index b1d49d37fdc..ccdde019087 100644
--- a/docs/framework/react/devtools.md
+++ b/docs/framework/react/devtools.md
@@ -78,7 +78,7 @@ function App() {
- Set this `true` if you want the dev tools to default to being open
- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "relative"`
- Defaults to `bottom-right`
- - The position of the React Query logo to open and close the devtools panel
+ - 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`
@@ -92,6 +92,9 @@ function App() {
- `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.
+- `theme?: "light" | "dark" | "system"`
+ - Defaults to `system`.
+ - Set this to change the theme of the devtools panel.
## Embedded Mode
@@ -124,7 +127,7 @@ function App() {
- Default: `{ height: '500px' }`
- Example: `{ height: '100%' }`
- Example: `{ height: '100%', width: '100%' }`
-- `onClose?: () => unknown`
+- `onClose?: () => void`
- Callback function that is called when the devtools panel is closed
- `client?: QueryClient`,
- Use this to use a custom QueryClient. Otherwise, the one from the nearest context will be used.
@@ -135,6 +138,9 @@ function App() {
- `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.
+- `theme?: "light" | "dark" | "system"`
+ - Defaults to `system`.
+ - Set this to change the theme of the devtools panel.
## Devtools in production
diff --git a/docs/framework/react/guides/advanced-ssr.md b/docs/framework/react/guides/advanced-ssr.md
index 3e1fdedff21..e0fc37544c7 100644
--- a/docs/framework/react/guides/advanced-ssr.md
+++ b/docs/framework/react/guides/advanced-ssr.md
@@ -31,7 +31,7 @@ The first step of any React Query setup is always to create a `queryClient` and
// Since QueryClientProvider relies on useContext under the hood, we have to put 'use client' on top
import {
- isServer,
+ environmentManager,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
@@ -51,7 +51,7 @@ function makeQueryClient() {
let browserQueryClient: QueryClient | undefined = undefined
function getQueryClient() {
- if (isServer) {
+ if (environmentManager.isServer()) {
// Server: always make a new query client
return makeQueryClient()
} else {
@@ -216,9 +216,9 @@ One neat thing about the examples above is that the only thing that is Next.js-s
In the SSR guide, we noted that you could get rid of the boilerplate of having `` in every route. This is not possible with Server Components.
-> NOTE: If you encounter a type error while using async Server Components with TypeScript versions lower than `5.1.3` and `@types/react` versions lower than `18.2.8`, it is recommended to update to the latest versions of both. Alternatively, you can use the temporary workaround of adding `{/* @ts-expect-error Server Component */}` when calling this component inside another. For more information, see [Async Server Component TypeScript Error](https://nextjs.org/docs/app/building-your-application/configuring/typescript#async-server-component-typescript-error) in the Next.js 13 docs.
+> NOTE: If you encounter a type error while using async Server Components with TypeScript versions lower than `5.1.3` and `@types/react` versions lower than `18.2.8`, it is recommended to update to the latest versions of both. Alternatively, you can use the temporary workaround of adding `{/* @ts-expect-error Server Component */}` when calling this component inside another. For more information, see [Async Server Component TypeScript Error](https://nextjs.org/docs/app/building-your-application/configuring/typescript#async-server-component-typescript-error) in the Next.js TypeScript docs.
-> NOTE: If you encounter an error `Only plain objects, and a few built-ins, can be passed to Server Actions. Classes or null prototypes are not supported.` make sure that you're **not** passing to queryFn a function reference, instead call the function because queryFn args has a bunch of properties and not all of it would be serializable. see [Server Action only works when queryFn isn't a reference](https://github.com/TanStack/query/issues/6264).
+> WARNING: We do **not** recommend using Next.js Server Actions to _fetch_ data in a `queryFn`. When called from the client, Server Actions [run serially, not in parallel](https://react.dev/reference/rsc/use-server#caveats), which conflicts with how React Query fetches and refetches queries. This can leave queries stuck in a pending state or cause the action to never run at all (see [#7934](https://github.com/TanStack/query/issues/7934)). Passing a Server Action reference to `queryFn` can also fail with `Only plain objects, and a few built-ins, can be passed to Server Actions...`, since you have to _call_ the action rather than pass it as a reference (see [#6264](https://github.com/TanStack/query/issues/6264)). For fetching data on the client, `fetch` from an API route or use an RPC layer such as tRPC instead. Server Actions remain a good fit for **mutations** (`useMutation`).
### Nesting Server Components
@@ -376,7 +376,7 @@ We will also need to move the `getQueryClient()` function out of our `app/provid
```tsx
// app/get-query-client.ts
import {
- isServer,
+ environmentManager,
QueryClient,
defaultShouldDehydrateQuery,
} from '@tanstack/react-query'
@@ -408,7 +408,7 @@ function makeQueryClient() {
let browserQueryClient: QueryClient | undefined = undefined
export function getQueryClient() {
- if (isServer) {
+ if (environmentManager.isServer()) {
// Server: always make a new query client
return makeQueryClient()
} else {
@@ -555,7 +555,7 @@ This ensures that only successfully resolved queries are persisted to storage, p
While we recommend the prefetching solution detailed above because it flattens request waterfalls both on the initial page load **and** any subsequent page navigation, there is an experimental way to skip prefetching altogether and still have streaming SSR work: `@tanstack/react-query-next-experimental`
-This package will allow you to fetch data on the server (in a Client Component) by just calling `useSuspenseQuery` in your component. Results will then be streamed from the server to the client as SuspenseBoundaries resolve. If you call `useSuspenseQuery` without wrapping it in a `` boundary, the HTML response won't start until the fetch resolves. This can be when you want depending on the situation, but keep in mind that this will hurt your TTFB.
+This package will allow you to fetch data on the server (in a Client Component) by just calling `useSuspenseQuery` in your component. Results will then be streamed from the server to the client as SuspenseBoundaries resolve. If you call `useSuspenseQuery` without wrapping it in a `` boundary, the HTML response won't start until the fetch resolves. This can be what you want depending on the situation, but keep in mind that this will hurt your TTFB.
To achieve this, wrap your app in the `ReactQueryStreamedHydration` component:
@@ -564,7 +564,7 @@ To achieve this, wrap your app in the `ReactQueryStreamedHydration` component:
'use client'
import {
- isServer,
+ environmentManager,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
@@ -586,7 +586,7 @@ function makeQueryClient() {
let browserQueryClient: QueryClient | undefined = undefined
function getQueryClient() {
- if (isServer) {
+ if (environmentManager.isServer()) {
// Server: always make a new query client
return makeQueryClient()
} else {
diff --git a/docs/framework/react/guides/important-defaults.md b/docs/framework/react/guides/important-defaults.md
index f17e777e566..1458ff9791d 100644
--- a/docs/framework/react/guides/important-defaults.md
+++ b/docs/framework/react/guides/important-defaults.md
@@ -14,6 +14,8 @@ Out of the box, TanStack Query is configured with **aggressive but sane** defaul
- set `staleTime` to `Infinity` to never trigger a refetch until the Query is [invalidated manually](./query-invalidation.md).
- set `staleTime` to `'static'` to **never** trigger a refetch, even if the Query is [invalidated manually](./query-invalidation.md).
+> `'static'` and `Infinity` both prevent staleness-based refetches, but `'static'` is stricter: `queryClient.invalidateQueries()` can invalidate a query with `staleTime: Infinity`, but has no effect on `staleTime: 'static'`. `refetchOnMount`, `refetchOnWindowFocus`, and `refetchOnReconnect` set to `"always"` are also blocked by `'static'`. Use `'static'` for data that cannot change while the app is running: feature flags fetched at boot, user permissions loaded at login, static reference tables. Use `Infinity` when you still want manual invalidation to work.
+
- Stale queries are refetched automatically in the background when:
- New instances of the query mount
- The window is refocused
@@ -21,7 +23,7 @@ Out of the box, TanStack Query is configured with **aggressive but sane** defaul
> Setting `staleTime` is the recommended way to avoid excessive refetches, but you can also customize the points in time for refetches by setting options like `refetchOnMount`, `refetchOnWindowFocus` and `refetchOnReconnect`.
-- Queries can optionally be configured with a `refetchInterval` to trigger refetches periodically, which is independent of the `staleTime` setting.
+- Queries can optionally be configured with a `refetchInterval` to trigger refetches periodically, which is independent of the `staleTime` setting. See [Polling](./polling.md) for details.
- Query results that have no more active instances of `useQuery`, `useInfiniteQuery` or query observers are labeled as "inactive" and remain in the cache in case they are used again at a later time.
- By default, "inactive" queries are garbage collected after **5 minutes**.
diff --git a/docs/framework/react/guides/polling.md b/docs/framework/react/guides/polling.md
new file mode 100644
index 00000000000..487a42f227e
--- /dev/null
+++ b/docs/framework/react/guides/polling.md
@@ -0,0 +1,109 @@
+---
+id: polling
+title: Polling
+---
+
+`refetchInterval` makes a query refetch on a timer. Set it to a number in milliseconds and the query runs every N ms while there's at least one active observer:
+
+[//]: # 'Example1'
+
+```tsx
+useQuery({
+ queryKey: ['prices'],
+ queryFn: fetchPrices,
+ refetchInterval: 5_000, // every 5 seconds
+})
+```
+
+[//]: # 'Example1'
+
+Polling is independent of `staleTime`. A query can be fresh and still poll on schedule; see [Important Defaults](./important-defaults.md) for how `staleTime` interacts with other refetch behaviors. `refetchInterval` fires on its own clock regardless of freshness.
+
+## Adapting the interval to query state
+
+Pass a function instead of a number to compute the interval from the current query. The function receives the `Query` object and should return a number in ms or `false` to stop polling:
+
+[//]: # 'Example2'
+
+```tsx
+useQuery({
+ queryKey: ['job', jobId],
+ queryFn: () => fetchJobStatus(jobId),
+ refetchInterval: (query) => {
+ // Stop polling once the job finishes
+ if (query.state.data?.status === 'complete') return false
+ return 2_000
+ },
+})
+```
+
+[//]: # 'Example2'
+
+Returning `false` clears the interval timer. If the query result changes so the function would return a positive number again, polling resumes automatically.
+
+## Background polling
+
+By default, polling pauses when the browser tab loses focus. For dashboards or any interface where data needs to stay current even while the user is in another tab, disable that behavior:
+
+[//]: # 'Example3'
+
+```tsx
+useQuery({
+ queryKey: ['portfolio'],
+ queryFn: fetchPortfolio,
+ refetchInterval: 30_000,
+ refetchIntervalInBackground: true,
+})
+```
+
+[//]: # 'Example3'
+
+## Pausing polling
+
+Pass a function to `refetchInterval` and close over component state to control when polling runs:
+
+[//]: # 'Example4'
+
+```tsx
+useQuery({
+ queryKey: ['prices', tokenAddress],
+ queryFn: () => fetchPrice(tokenAddress),
+ refetchInterval: () => {
+ if (!tokenAddress || isPaused) return false
+ return 15_000
+ },
+})
+```
+
+[//]: # 'Example4'
+
+## Polling with offline support
+
+TanStack Query detects connectivity by listening to the browser's `online` and `offline` events. In environments where those events don't fire reliably (Electron, some embedded WebViews), set `networkMode: 'always'` to skip the connectivity check:
+
+[//]: # 'Example5'
+
+```tsx
+useQuery({
+ queryKey: ['chainStatus'],
+ queryFn: fetchChainStatus,
+ refetchInterval: 10_000,
+ networkMode: 'always',
+})
+```
+
+[//]: # 'Example5'
+
+For more on network modes, see [Network Mode](./network-mode.md).
+
+## Note on deduplication
+
+Each `QueryObserver` (each component using `useQuery` with `refetchInterval`) runs its own timer. Two components subscribed to the same key with `refetchInterval: 5000` each fire their timer every 5 seconds. What gets deduplicated is concurrent in-flight fetches: if two timers fire at the same time, only one network request goes out. The timers are observer-level; the deduplication is query-level.
+
+[//]: # 'ReactNative'
+
+## Non-browser environments
+
+For non-browser runtimes like React Native, the standard `online`/`offline` and focus events aren't available. The [React Native guide](../react-native.md) covers how to connect `focusManager` and `onlineManager` to native app state APIs.
+
+[//]: # 'ReactNative'
diff --git a/docs/framework/react/guides/query-functions.md b/docs/framework/react/guides/query-functions.md
index 4fa621c6977..e121bab54a2 100644
--- a/docs/framework/react/guides/query-functions.md
+++ b/docs/framework/react/guides/query-functions.md
@@ -5,6 +5,8 @@ title: Query Functions
A query function can be literally any function that **returns a promise**. The promise that is returned should either **resolve the data** or **throw an error**.
+On success, the resolved value may be anything **except `undefined`**. Queries that resolve to `undefined` will be [treated as failed](https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-react-query-4#undefined-is-an-illegal-cache-value-for-successful-queries). To store "nothing" as a successful result in the query cache, resolve `null` instead.
+
All of the following are valid query function configurations:
[//]: # 'Example'
diff --git a/docs/framework/react/guides/suspense.md b/docs/framework/react/guides/suspense.md
index 7e8e0456619..7c48e65a14c 100644
--- a/docs/framework/react/guides/suspense.md
+++ b/docs/framework/react/guides/suspense.md
@@ -120,7 +120,7 @@ To achieve this, wrap your app in the `ReactQueryStreamedHydration` component:
'use client'
import {
- isServer,
+ environmentManager,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
@@ -142,7 +142,7 @@ function makeQueryClient() {
let browserQueryClient: QueryClient | undefined = undefined
function getQueryClient() {
- if (isServer) {
+ if (environmentManager.isServer()) {
// Server: always make a new query client
return makeQueryClient()
} else {
diff --git a/docs/framework/react/reference/useQuery.md b/docs/framework/react/reference/useQuery.md
index c17fe8b79db..b02775a62cf 100644
--- a/docs/framework/react/reference/useQuery.md
+++ b/docs/framework/react/reference/useQuery.md
@@ -86,8 +86,9 @@ const {
- If set to a `number`, e.g. `3`, failed queries will retry until the failed query count meets that number.
- If set to a function, it will be called with `failureCount` (starting at `0` for the first retry) and `error` to determine if a retry should be attempted.
- defaults to `3` on the client and `0` on the server
-- `retryOnMount: boolean`
- - If set to `false`, the query will not be retried on mount if it contains an error. Defaults to `true`.
+- `retryOnMount: boolean | (query: Query) => boolean`
+ - If set to `false`, the query will not be retried on mount if it contains an error and has no data. Defaults to `true`.
+ - If set to a function, the function will be executed with the query to compute the value.
- `retryDelay: number | (retryAttempt: number, error: TError) => number`
- This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds.
- A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff.
diff --git a/docs/framework/solid/devtools.md b/docs/framework/solid/devtools.md
index 97b465d6727..b6a2cca2480 100644
--- a/docs/framework/solid/devtools.md
+++ b/docs/framework/solid/devtools.md
@@ -70,18 +70,70 @@ function App() {
- `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"`
+- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "relative"`
- Defaults to `bottom-right`
- - The position of the Solid Query logo to open and close the devtools panel
+ - The position of the TanStack logo to open and close the devtools panel
- `position?: "top" | "bottom" | "left" | "right"`
- Defaults to `bottom`
- The position of the Solid 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}`
+- `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.
+- `theme?: "light" | "dark" | "system"`
+ - Defaults to `system`.
+ - Set this to change the theme of the devtools panel.
+
+## Embedded Mode
+
+Embedded mode will show the development tools as a fixed element in your application, so you can use our panel in your own development tools.
+
+Place the following code as high in your Solid app as you can. The closer it is to the root of the page, the better it will work!
+
+```tsx
+import { createSignal, Show } from 'solid-js'
+import { SolidQueryDevtoolsPanel } from '@tanstack/solid-query-devtools'
+
+function App() {
+ const [isOpen, setIsOpen] = createSignal(false)
+
+ return (
+
+ {/* The rest of your application */}
+
+
+ setIsOpen(false)} />
+
+
+ )
+}
+```
+
+### Options
+
+- `style?: JSX.CSSProperties`
+ - Custom styles for the devtools panel
+ - Default: `{ height: '500px' }`
+ - Example: `{ height: '100%' }`
+ - Example: `{ height: '100%', width: '100%' }`
+- `onClose?: () => void`
+ - Callback function that is called when the devtools panel is closed
+- `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.
+- `theme?: "light" | "dark" | "system"`
+ - Defaults to `system`.
+ - Set this to change the theme of the devtools panel.
diff --git a/docs/framework/solid/guides/polling.md b/docs/framework/solid/guides/polling.md
new file mode 100644
index 00000000000..9410627ebfc
--- /dev/null
+++ b/docs/framework/solid/guides/polling.md
@@ -0,0 +1,73 @@
+---
+id: polling
+title: Polling
+ref: docs/framework/react/guides/polling.md
+replace: { '@tanstack/react-query': '@tanstack/solid-query' }
+---
+
+[//]: # 'Example1'
+
+```tsx
+useQuery(() => ({
+ queryKey: ['prices'],
+ queryFn: fetchPrices,
+ refetchInterval: 5_000, // every 5 seconds
+}))
+```
+
+[//]: # 'Example1'
+[//]: # 'Example2'
+
+```tsx
+useQuery(() => ({
+ queryKey: ['job', jobId],
+ queryFn: () => fetchJobStatus(jobId),
+ refetchInterval: (query) => {
+ // Stop polling once the job finishes
+ if (query.state.data?.status === 'complete') return false
+ return 2_000
+ },
+}))
+```
+
+[//]: # 'Example2'
+[//]: # 'Example3'
+
+```tsx
+useQuery(() => ({
+ queryKey: ['portfolio'],
+ queryFn: fetchPortfolio,
+ refetchInterval: 30_000,
+ refetchIntervalInBackground: true,
+}))
+```
+
+[//]: # 'Example3'
+[//]: # 'Example4'
+
+```tsx
+useQuery(() => ({
+ queryKey: ['prices', tokenAddress],
+ queryFn: () => fetchPrice(tokenAddress),
+ refetchInterval: () => {
+ if (!tokenAddress || isPaused) return false
+ return 15_000
+ },
+}))
+```
+
+[//]: # 'Example4'
+[//]: # 'Example5'
+
+```tsx
+useQuery(() => ({
+ queryKey: ['chainStatus'],
+ queryFn: fetchChainStatus,
+ refetchInterval: 10_000,
+ networkMode: 'always',
+}))
+```
+
+[//]: # 'Example5'
+[//]: # 'ReactNative'
+[//]: # 'ReactNative'
diff --git a/docs/framework/solid/reference/useQuery.md b/docs/framework/solid/reference/useQuery.md
index 38b9751d758..876c5c99729 100644
--- a/docs/framework/solid/reference/useQuery.md
+++ b/docs/framework/solid/reference/useQuery.md
@@ -277,8 +277,9 @@ function App() {
- If `true`, failed queries will retry infinitely.
- If set to a `number`, e.g. `3`, failed queries will retry until the failed query count meets that number.
- defaults to `3` on the client and `0` on the server
- - ##### `retryOnMount: boolean`
- - If set to `false`, the query will not be retried on mount if it contains an error. Defaults to `true`.
+ - ##### `retryOnMount: boolean | (query: Query) => boolean`
+ - If set to `false`, the query will not be retried on mount if it contains an error and has no data. Defaults to `true`.
+ - If set to a function, the function will be executed with the query to compute the value.
- ##### `retryDelay: number | (retryAttempt: number, error: TError) => number`
- This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds.
- A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff.
diff --git a/docs/framework/svelte/devtools.md b/docs/framework/svelte/devtools.md
index efdb77e922d..179690c2a63 100644
--- a/docs/framework/svelte/devtools.md
+++ b/docs/framework/svelte/devtools.md
@@ -72,7 +72,7 @@ Place the following code as high in your Svelte app as you can. The closer it is
- The position of the Svelte 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}`
+- `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.
diff --git a/docs/framework/vue/devtools.md b/docs/framework/vue/devtools.md
index 666058e27a9..a32a5e0f5ba 100644
--- a/docs/framework/vue/devtools.md
+++ b/docs/framework/vue/devtools.md
@@ -65,52 +65,56 @@ import { VueQueryDevtools } from '@tanstack/vue-query-devtools'
- `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"`
+- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "relative"`
- Defaults to `bottom-right`.
- - The position of the React Query logo to open and close the devtools panel.
+ - The position of the TanStack logo to open and close the devtools panel.
- `position?: "top" | "bottom" | "left" | "right"`
- Defaults to `bottom`.
- - The position of the React Query devtools panel.
+ - The position of the Vue 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}`
+- `errorTypes?: { name: string; initializer: (query: Query) => TError}[]`
- Use this to predefine some errors that can be triggered on your queries. The 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.
+- `theme?: "light" | "dark" | "system"`
+ - Defaults to `system`.
+ - Set this to change the theme of the devtools panel.
## Embedded Mode
Embedded mode will show the development tools as a fixed element in your application, so you can use our panel in your own development tools.
-Place the following code as high in your React app as you can. The closer it is to the root of the page, the better it will work!
+Place the following code as high in your Vue app as you can. The closer it is to the root of the page, the better it will work!
```vue
The app!
-
-
+
+
```
### Options
-- `style?: React.CSSProperties`
+- `style?: Partial`
- Custom styles for the devtools panel
- Default: `{ height: '500px' }`
- Example: `{ height: '100%' }`
- Example: `{ height: '100%', width: '100%' }`
-- `onClose?: () => unknown`
+- `onClose?: () => void`
- Callback function that is called when the devtools panel is closed
- `client?: QueryClient`,
- Use this to use a custom QueryClient. Otherwise, the one from the nearest context will be used.
@@ -121,6 +125,9 @@ function toggleDevtools() {
- `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.
+- `theme?: "light" | "dark" | "system"`
+ - Defaults to `system`.
+ - Set this to change the theme of the devtools panel.
## Traditional Devtools
diff --git a/docs/framework/vue/guides/polling.md b/docs/framework/vue/guides/polling.md
new file mode 100644
index 00000000000..1f096cd007d
--- /dev/null
+++ b/docs/framework/vue/guides/polling.md
@@ -0,0 +1,9 @@
+---
+id: polling
+title: Polling
+ref: docs/framework/react/guides/polling.md
+replace: { '@tanstack/react-query': '@tanstack/vue-query' }
+---
+
+[//]: # 'ReactNative'
+[//]: # 'ReactNative'
diff --git a/docs/framework/vue/reference/mutationOptions.md b/docs/framework/vue/reference/mutationOptions.md
new file mode 100644
index 00000000000..b34296ad545
--- /dev/null
+++ b/docs/framework/vue/reference/mutationOptions.md
@@ -0,0 +1,5 @@
+---
+id: mutationOptions
+title: mutationOptions
+ref: docs/framework/react/reference/mutationOptions.md
+---
diff --git a/docs/framework/vue/reference/usePrefetchInfiniteQuery.md b/docs/framework/vue/reference/usePrefetchInfiniteQuery.md
new file mode 100644
index 00000000000..c7af728d36d
--- /dev/null
+++ b/docs/framework/vue/reference/usePrefetchInfiniteQuery.md
@@ -0,0 +1,6 @@
+---
+id: usePrefetchInfiniteQuery
+title: usePrefetchInfiniteQuery
+ref: docs/framework/react/reference/usePrefetchInfiniteQuery.md
+replace: { '@tanstack/react-query': '@tanstack/vue-query' }
+---
diff --git a/docs/framework/vue/reference/usePrefetchQuery.md b/docs/framework/vue/reference/usePrefetchQuery.md
new file mode 100644
index 00000000000..e518a62ef84
--- /dev/null
+++ b/docs/framework/vue/reference/usePrefetchQuery.md
@@ -0,0 +1,6 @@
+---
+id: usePrefetchQuery
+title: usePrefetchQuery
+ref: docs/framework/react/reference/usePrefetchQuery.md
+replace: { '@tanstack/react-query': '@tanstack/vue-query' }
+---
diff --git a/docs/reference/QueryCache.md b/docs/reference/QueryCache.md
index 09a9c8e5357..5c7251540eb 100644
--- a/docs/reference/QueryCache.md
+++ b/docs/reference/QueryCache.md
@@ -22,7 +22,7 @@ const queryCache = new QueryCache({
},
})
-const query = queryCache.find(['posts'])
+const query = queryCache.find({ queryKey: ['posts'] })
```
Its available methods are:
@@ -52,12 +52,13 @@ Its available methods are:
> Note: This is not typically needed for most applications, but can come in handy when needing more information about a query in rare scenarios (eg. Looking at the query.state.dataUpdatedAt timestamp to decide whether a query is fresh enough to be used as an initial value)
```tsx
-const query = queryCache.find(queryKey)
+const query = queryCache.find({ queryKey })
```
**Options**
-- `filters?: QueryFilters`: [Query Filters](../framework/react/guides/filters#query-filters)
+- `filters: QueryFilters`: [Query Filters](../framework/react/guides/filters#query-filters)
+ - `queryKey: QueryKey`: [Query Keys](../framework/react/guides/query-keys.md)
**Returns**
@@ -71,12 +72,11 @@ const query = queryCache.find(queryKey)
> Note: This is not typically needed for most applications, but can come in handy when needing more information about a query in rare scenarios
```tsx
-const queries = queryCache.findAll(queryKey)
+const queries = queryCache.findAll({ queryKey })
```
**Options**
-- `queryKey?: QueryKey`: [Query Keys](../framework/react/guides/query-keys.md)
- `filters?: QueryFilters`: [Query Filters](../framework/react/guides/filters.md#query-filters)
**Returns**
diff --git a/docs/reference/QueryClient.md b/docs/reference/QueryClient.md
index 13bde1ffad0..3c9e1b31c27 100644
--- a/docs/reference/QueryClient.md
+++ b/docs/reference/QueryClient.md
@@ -250,7 +250,7 @@ This distinction is more a "convenience" for ts devs that know which structure w
## `queryClient.setQueryData`
-`setQueryData` is a synchronous function that can be used to immediately update a query's cached data. If the query does not exist, it will be created. **If the query is not utilized by a query hook in the default `gcTime` of 5 minutes, the query will be garbage collected**. To update multiple queries at once and match query keys partially, you need to use [`queryClient.setQueriesData`](#queryclientsetqueriesdata) instead.
+`setQueryData` is a synchronous function that can be used to immediately update a query's cached data. If the query does not exist, it will be created. **If the query is not utilized by a query hook within the default `gcTime`, the query will be garbage collected. If the default `gcTime` has not been configured, it defaults to 5 minutes.** To update multiple queries at once and match query keys partially, you need to use [`queryClient.setQueriesData`](#queryclientsetqueriesdata) instead.
> The difference between using `setQueryData` and `fetchQuery` is that `setQueryData` is sync and assumes that you already synchronously have the data available. If you need to fetch the data asynchronously, it's suggested that you either refetch the query key or use `fetchQuery` to handle the asynchronous fetch.
@@ -352,6 +352,11 @@ await queryClient.invalidateQueries(
- Per default, a currently running request will be cancelled before a new request is made
- When set to `false`, no refetch will be made if there is already a request running.
+**Notes**
+
+- Unlike [`refetchQueries`](#queryclientrefetchqueries), `invalidateQueries` marks matching queries as invalidated and then refetches `active` queries (unless otherwise specified with the `refetchType` option).
+- Unlike [`removeQueries`](#queryclientremovequeries), `invalidateQueries` keeps matching queries in the cache.
+
## `queryClient.refetchQueries`
The `refetchQueries` method can be used to refetch queries based on certain conditions.
@@ -395,6 +400,7 @@ This function returns a promise that will resolve when all of the queries are do
- Queries that are "disabled" because they only have disabled Observers will never be refetched.
- Queries that are "static" because they only have Observers with a Static StaleTime will never be refetched.
+- Unlike [`invalidateQueries`](#queryclientinvalidatequeries), `refetchQueries` refetches all matching queries.
## `queryClient.cancelQueries`
@@ -434,6 +440,10 @@ queryClient.removeQueries({ queryKey, exact: true })
This method does not return anything
+**Notes**
+
+- Unlike [`invalidateQueries`](#queryclientinvalidatequeries) or [`refetchQueries`](#queryclientrefetchqueries), `removeQueries` removes matching queries from the cache instead of refetching them.
+
## `queryClient.resetQueries`
The `resetQueries` method can be used to reset queries in the cache to their
diff --git a/eslint.config.js b/eslint.config.js
index ae923ac2254..20709d68c25 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -53,10 +53,14 @@ export default [
plugins: { vitest },
rules: {
...vitest.configs.recommended.rules,
+ 'vitest/consistent-test-it': [
+ 'error',
+ { fn: 'it', withinDescribe: 'it' },
+ ],
'vitest/no-standalone-expect': [
'error',
{
- additionalTestBlockFunctions: ['testIf'],
+ additionalTestBlockFunctions: ['itIf'],
},
],
},
diff --git a/examples/angular/auto-refetching/README.md b/examples/angular/auto-refetching/README.md
index 571955a305d..4a70c6af6e7 100644
--- a/examples/angular/auto-refetching/README.md
+++ b/examples/angular/auto-refetching/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/auto-refetching/package.json b/examples/angular/auto-refetching/package.json
index 0e06fe93233..ffa0ba4bb5a 100644
--- a/examples/angular/auto-refetching/package.json
+++ b/examples/angular/auto-refetching/package.json
@@ -13,7 +13,7 @@
"@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/basic-persister/README.md b/examples/angular/basic-persister/README.md
index 47d5931979a..6c79fc36193 100644
--- a/examples/angular/basic-persister/README.md
+++ b/examples/angular/basic-persister/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/basic-persister/package.json b/examples/angular/basic-persister/package.json
index 44784988078..b227eed959f 100644
--- a/examples/angular/basic-persister/package.json
+++ b/examples/angular/basic-persister/package.json
@@ -13,9 +13,9 @@
"@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
- "@tanstack/angular-query-persist-client": "^5.62.32",
- "@tanstack/query-async-storage-persister": "^5.90.27",
+ "@tanstack/angular-query-experimental": "^5.101.0",
+ "@tanstack/angular-query-persist-client": "^5.101.0",
+ "@tanstack/query-async-storage-persister": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/basic/README.md b/examples/angular/basic/README.md
index 15f2ed2f4a2..61eb487a22c 100644
--- a/examples/angular/basic/README.md
+++ b/examples/angular/basic/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/basic/package.json b/examples/angular/basic/package.json
index 2bdbba2ff44..c87b2b5bf7d 100644
--- a/examples/angular/basic/package.json
+++ b/examples/angular/basic/package.json
@@ -13,7 +13,7 @@
"@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/devtools-panel/README.md b/examples/angular/devtools-panel/README.md
index 849d0a9d4e0..729ce68dc49 100644
--- a/examples/angular/devtools-panel/README.md
+++ b/examples/angular/devtools-panel/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/devtools-panel/package.json b/examples/angular/devtools-panel/package.json
index 5970e53c1d2..0376ced8449 100644
--- a/examples/angular/devtools-panel/package.json
+++ b/examples/angular/devtools-panel/package.json
@@ -14,7 +14,7 @@
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
"@angular/router": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/infinite-query-with-max-pages/README.md b/examples/angular/infinite-query-with-max-pages/README.md
index fce960f6a35..4f308448f5f 100644
--- a/examples/angular/infinite-query-with-max-pages/README.md
+++ b/examples/angular/infinite-query-with-max-pages/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/infinite-query-with-max-pages/package.json b/examples/angular/infinite-query-with-max-pages/package.json
index 96701d77008..f7bc3b933cc 100644
--- a/examples/angular/infinite-query-with-max-pages/package.json
+++ b/examples/angular/infinite-query-with-max-pages/package.json
@@ -13,7 +13,7 @@
"@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/optimistic-updates/README.md b/examples/angular/optimistic-updates/README.md
index 583897ad45d..bcffae54d27 100644
--- a/examples/angular/optimistic-updates/README.md
+++ b/examples/angular/optimistic-updates/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/optimistic-updates/package.json b/examples/angular/optimistic-updates/package.json
index 8bbe39a2005..10024dc6b15 100644
--- a/examples/angular/optimistic-updates/package.json
+++ b/examples/angular/optimistic-updates/package.json
@@ -14,7 +14,7 @@
"@angular/core": "^20.0.0",
"@angular/forms": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/pagination/README.md b/examples/angular/pagination/README.md
index fd58c455860..6e113c75664 100644
--- a/examples/angular/pagination/README.md
+++ b/examples/angular/pagination/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/pagination/package.json b/examples/angular/pagination/package.json
index 8f583a65d54..8164f6ea323 100644
--- a/examples/angular/pagination/package.json
+++ b/examples/angular/pagination/package.json
@@ -13,7 +13,7 @@
"@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/query-options-from-a-service/README.md b/examples/angular/query-options-from-a-service/README.md
index f9e940480ac..40bce6275f8 100644
--- a/examples/angular/query-options-from-a-service/README.md
+++ b/examples/angular/query-options-from-a-service/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/query-options-from-a-service/package.json b/examples/angular/query-options-from-a-service/package.json
index e17c58742c7..a95aaff2726 100644
--- a/examples/angular/query-options-from-a-service/package.json
+++ b/examples/angular/query-options-from-a-service/package.json
@@ -14,7 +14,7 @@
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
"@angular/router": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/router/README.md b/examples/angular/router/README.md
index 0429048cb9c..ea37ad5d945 100644
--- a/examples/angular/router/README.md
+++ b/examples/angular/router/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/router/package.json b/examples/angular/router/package.json
index c504dbf6445..68d4e07f5d8 100644
--- a/examples/angular/router/package.json
+++ b/examples/angular/router/package.json
@@ -14,7 +14,7 @@
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
"@angular/router": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/rxjs/README.md b/examples/angular/rxjs/README.md
index bc63a82b7f2..5603b0de263 100644
--- a/examples/angular/rxjs/README.md
+++ b/examples/angular/rxjs/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/rxjs/package.json b/examples/angular/rxjs/package.json
index d2b4e449366..4859e692f81 100644
--- a/examples/angular/rxjs/package.json
+++ b/examples/angular/rxjs/package.json
@@ -14,7 +14,7 @@
"@angular/core": "^20.0.0",
"@angular/forms": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/angular/simple/README.md b/examples/angular/simple/README.md
index 35939257ca9..b2acfd071ab 100644
--- a/examples/angular/simple/README.md
+++ b/examples/angular/simple/README.md
@@ -2,5 +2,5 @@
To run this example:
-- `npm install` or `yarn` or `pnpm i` or `bun i`
-- `npm run start` or `yarn start` or `pnpm start` or `bun start`
+- `pnpm install`
+- `pnpm start`
diff --git a/examples/angular/simple/package.json b/examples/angular/simple/package.json
index f407d3ca1fe..0e613ca6e45 100644
--- a/examples/angular/simple/package.json
+++ b/examples/angular/simple/package.json
@@ -13,7 +13,7 @@
"@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/platform-browser": "^20.0.0",
- "@tanstack/angular-query-experimental": "^5.90.28",
+ "@tanstack/angular-query-experimental": "^5.101.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
diff --git a/examples/lit/basic/CHANGELOG.md b/examples/lit/basic/CHANGELOG.md
new file mode 100644
index 00000000000..6047b494b38
--- /dev/null
+++ b/examples/lit/basic/CHANGELOG.md
@@ -0,0 +1,8 @@
+# @tanstack/query-example-lit-basic
+
+## 0.0.2
+
+### Patch Changes
+
+- Updated dependencies [[`4082894`](https://github.com/TanStack/query/commit/4082894509f31376ebeb8514cc3e167bbbfc7c46)]:
+ - @tanstack/lit-query@0.2.0
diff --git a/examples/lit/basic/README.md b/examples/lit/basic/README.md
new file mode 100644
index 00000000000..6d79ad06c1a
--- /dev/null
+++ b/examples/lit/basic/README.md
@@ -0,0 +1,5 @@
+# Example
+
+To run this example from the repo root:
+
+- `pnpm --dir examples/lit/basic run dev`
diff --git a/examples/lit/basic/basic-query.html b/examples/lit/basic/basic-query.html
new file mode 100644
index 00000000000..19de73348a1
--- /dev/null
+++ b/examples/lit/basic/basic-query.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Lit Query Basic Example
+
+
+
+
+
+
diff --git a/examples/lit/basic/config/port.d.ts b/examples/lit/basic/config/port.d.ts
new file mode 100644
index 00000000000..12e9b85cc4d
--- /dev/null
+++ b/examples/lit/basic/config/port.d.ts
@@ -0,0 +1 @@
+export const DEMO_PORT: number
diff --git a/examples/lit/basic/config/port.js b/examples/lit/basic/config/port.js
new file mode 100644
index 00000000000..bff39bff2ee
--- /dev/null
+++ b/examples/lit/basic/config/port.js
@@ -0,0 +1,22 @@
+const DEFAULT_DEMO_PORT = 4173
+const envPort = process.env.DEMO_PORT
+
+function resolvePort() {
+ if (!envPort) {
+ return DEFAULT_DEMO_PORT
+ }
+
+ const parsedPort = Number.parseInt(envPort, 10)
+ const isValidPort =
+ Number.isInteger(parsedPort) && parsedPort > 0 && parsedPort <= 65535
+
+ if (!isValidPort) {
+ throw new Error(
+ `Invalid DEMO_PORT "${envPort}". Expected an integer between 1 and 65535.`,
+ )
+ }
+
+ return parsedPort
+}
+
+export const DEMO_PORT = resolvePort()
diff --git a/examples/lit/basic/index.html b/examples/lit/basic/index.html
new file mode 100644
index 00000000000..a2962e70475
--- /dev/null
+++ b/examples/lit/basic/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ TanStack Lit Query E2E Demo
+
+
+
+
+
+
diff --git a/examples/lit/basic/lifecycle-contract.html b/examples/lit/basic/lifecycle-contract.html
new file mode 100644
index 00000000000..5d0f5e5e5a1
--- /dev/null
+++ b/examples/lit/basic/lifecycle-contract.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ TanStack Lit Query Lifecycle Contract Fixture
+
+
+
+
+
+
diff --git a/examples/lit/basic/mutation.html b/examples/lit/basic/mutation.html
new file mode 100644
index 00000000000..1d5de500efb
--- /dev/null
+++ b/examples/lit/basic/mutation.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Lit Query Mutation Example
+
+
+
+
+
+
diff --git a/examples/lit/basic/package.json b/examples/lit/basic/package.json
new file mode 100644
index 00000000000..63d3825dd10
--- /dev/null
+++ b/examples/lit/basic/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "@tanstack/query-example-lit-basic",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc --noEmit && vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@tanstack/lit-query": "^0.2.7",
+ "@tanstack/query-core": "^5.101.0",
+ "lit": "^3.3.1"
+ },
+ "devDependencies": {
+ "typescript": "5.8.3",
+ "vite": "^6.4.1"
+ }
+}
diff --git a/examples/lit/basic/src/basic-query.ts b/examples/lit/basic/src/basic-query.ts
new file mode 100644
index 00000000000..5cc208d0174
--- /dev/null
+++ b/examples/lit/basic/src/basic-query.ts
@@ -0,0 +1,90 @@
+import { LitElement, html } from 'lit'
+import {
+ QueryClient,
+ QueryClientProvider,
+ createQueryController,
+} from '@tanstack/lit-query'
+import { fetchTodosFromServer, resetTodoApi } from './todoApi'
+import type { TodosResponse } from './todoApi'
+
+resetTodoApi()
+
+const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: { retry: false },
+ },
+})
+
+class BasicQueryProvider extends QueryClientProvider {
+ constructor() {
+ super()
+ this.client = queryClient
+ }
+
+ protected override createRenderRoot(): HTMLElement | DocumentFragment {
+ return this
+ }
+}
+
+customElements.define('basic-query-provider', BasicQueryProvider)
+
+class BasicQueryExample extends LitElement {
+ private readonly todos = createQueryController(this, {
+ queryKey: ['todos'],
+ queryFn: fetchTodosFromServer,
+ })
+
+ protected override createRenderRoot(): HTMLElement | DocumentFragment {
+ return this
+ }
+
+ render() {
+ const query = this.todos()
+ return html`
+
+