For Chrome, Firefox, and Edge users: Third-party browser extensions are available for debugging TanStack Query directly in browser DevTools. These provide the same functionality as the framework-specific devtools packages:
The devtools help you debug and inspect your queries and mutations. You can enable the devtools by adding withDevtools to provideTanStackQuery.
By default, Angular Query Devtools are only included in development mode bundles, so you don't need to worry about excluding them during a production build.
import {
QueryClient,
provideTanStackQuery,
} from '@tanstack/angular-query-experimental'
import { withDevtools } from '@tanstack/angular-query-experimental/devtools'
export const appConfig: ApplicationConfig = {
providers: [provideTanStackQuery(new QueryClient(), withDevtools())],
}
import {
QueryClient,
provideTanStackQuery,
} from '@tanstack/angular-query-experimental'
import { withDevtools } from '@tanstack/angular-query-experimental/devtools'
export const appConfig: ApplicationConfig = {
providers: [provideTanStackQuery(new QueryClient(), withDevtools())],
}
Devtools are automatically excluded from production builds. However, it might be desirable to lazy load the devtools in production.
To use withDevtools in production builds, import using the production sub-path. The function exported from the production subpath is identical to the main one, but won't be excluded from production builds.
import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
To control when devtools are loaded, you can use the loadDevtools option.
When not setting the option or setting it to 'auto', the devtools will be loaded automatically only when Angular runs in development mode.
import { withDevtools } from '@tanstack/angular-query-experimental/devtools'
provideTanStackQuery(new QueryClient(), withDevtools())
// which is equivalent to
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: 'auto' })),
)
import { withDevtools } from '@tanstack/angular-query-experimental/devtools'
provideTanStackQuery(new QueryClient(), withDevtools())
// which is equivalent to
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: 'auto' })),
)
When setting the option to true, the devtools will be loaded in both development and production mode.
This is useful if you want to load devtools based on Angular environment configurations. E.g. you could set this to true when the application is running on your production build staging environment.
import { environment } from './environments/environment'
// Make sure to use the production sub-path to load devtools in production builds
import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: environment.loadDevtools })),
)
import { environment } from './environments/environment'
// Make sure to use the production sub-path to load devtools in production builds
import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: environment.loadDevtools })),
)
When setting the option to false, the devtools will not be loaded.
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: false })),
)
provideTanStackQuery(
new QueryClient(),
withDevtools(() => ({ loadDevtools: false })),
)
Options are passed to withDevtools from a callback function to support reactivity through signals. In the following example a signal is created from a RxJS observable that emits on a keyboard shortcut. When the derived signal is set to true, the devtools are lazily loaded.
The example below always loads devtools in development mode and loads on-demand in production mode when a keyboard shortcut is pressed.
import { Injectable, isDevMode } from '@angular/core'
import { fromEvent, map, scan } from 'rxjs'
import { toSignal } from '@angular/core/rxjs-interop'
@Injectable({ providedIn: 'root' })
export class DevtoolsOptionsManager {
loadDevtools = toSignal(
fromEvent<KeyboardEvent>(document, 'keydown').pipe(
map(
(event): boolean =>
event.metaKey && event.ctrlKey && event.shiftKey && event.key === 'D',
),
scan((acc, curr) => acc || curr, isDevMode()),
),
{
initialValue: isDevMode(),
},
)
}
import { Injectable, isDevMode } from '@angular/core'
import { fromEvent, map, scan } from 'rxjs'
import { toSignal } from '@angular/core/rxjs-interop'
@Injectable({ providedIn: 'root' })
export class DevtoolsOptionsManager {
loadDevtools = toSignal(
fromEvent<KeyboardEvent>(document, 'keydown').pipe(
map(
(event): boolean =>
event.metaKey && event.ctrlKey && event.shiftKey && event.key === 'D',
),
scan((acc, curr) => acc || curr, isDevMode()),
),
{
initialValue: isDevMode(),
},
)
}
If you want to use an injectable such as a service in the callback you can use deps. The injected value will be passed as parameter to the callback function.
This is similar to deps in Angular's useFactory provider.
// ...
// 👇 Note we import from the production sub-path to enable devtools lazy loading in production builds
import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideTanStackQuery(
new QueryClient(),
withDevtools(
(devToolsOptionsManager: DevtoolsOptionsManager) => ({
loadDevtools: devToolsOptionsManager.loadDevtools(),
}),
{
// `deps` is used to inject and pass `DevtoolsOptionsManager` to the `withDevtools` callback.
deps: [DevtoolsOptionsManager],
},
),
),
],
}
// ...
// 👇 Note we import from the production sub-path to enable devtools lazy loading in production builds
import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideTanStackQuery(
new QueryClient(),
withDevtools(
(devToolsOptionsManager: DevtoolsOptionsManager) => ({
loadDevtools: devToolsOptionsManager.loadDevtools(),
}),
{
// `deps` is used to inject and pass `DevtoolsOptionsManager` to the `withDevtools` callback.
deps: [DevtoolsOptionsManager],
},
),
),
],
}
Of these options loadDevtools, client, position, errorTypes, buttonPosition, and initialIsOpen support reactivity through signals.