Angular Query DevTools help you visualize all of the inner workings of TanStack Query and provide a better debugging experience. DevTools display active, inactive, and stale queries, along with their data and cache status.
Installation
The DevTools are included as an optional peer dependency. Install them separately:
npm install @tanstack/query-devtools
The devtools package is listed as an optionalDependency in Angular Query, so you may see warnings during installation if you skip it. This is normal.
Basic Setup
The easiest way to use DevTools is with withDevtools(), which automatically displays them in development mode:
import { bootstrapApplication } from '@angular/platform-browser'
import {
provideTanStackQuery ,
QueryClient ,
withDevtools
} from '@tanstack/angular-query-experimental'
import { AppComponent } from './app/app.component'
export const appConfig : ApplicationConfig = {
providers: [
provideTanStackQuery (
new QueryClient (),
withDevtools () // Enables devtools in development mode
)
]
}
bootstrapApplication ( AppComponent , appConfig )
DevTools are imported dynamically using code splitting
They only load in development mode by default (isDevMode() is true)
A floating button appears in the bottom-right corner of your app
Click the button to open/close the DevTools panel
Development vs Production
In production builds, withDevtools() provides a stub implementation that does nothing, ensuring zero bundle size impact.
Configuration Options
Customize DevTools behavior by passing options to withDevtools():
import {
provideTanStackQuery ,
QueryClient ,
withDevtools ,
isDevMode
} from '@tanstack/angular-query-experimental'
export const appConfig : ApplicationConfig = {
providers: [
provideTanStackQuery (
new QueryClient (),
withDevtools (() => ({
initialIsOpen: false ,
buttonPosition: 'bottom-left' ,
position: 'bottom' ,
errorTypes: [{ name: 'Error' , initializer : ( value ) => new Error ( value ) }],
loadDevtools: isDevMode () // Explicitly control loading
}))
)
]
}
Available Options
If true, the DevTools panel will be open by default when the page loads.
buttonPosition
'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
default: "'bottom-right'"
Position of the floating DevTools toggle button.
position
'top' | 'bottom' | 'left' | 'right'
default: "'bottom'"
Side of the screen where the DevTools panel appears.
loadDevtools
boolean
default: "isDevMode()"
Controls whether DevTools should load. By default, only loads in development mode.
Optionally specify a different QueryClient. By default, uses the injected QueryClient.
Configure error types for error filtering in DevTools. errorTypes : [
{ name: 'Error' , initializer : ( value ) => new Error ( value ) },
{ name: 'CustomError' , initializer : ( value ) => new CustomError ( value ) }
]
Reactive Configuration
You can make DevTools options reactive by reading signals or other dependencies:
import { InjectionToken } from '@angular/core'
import {
provideTanStackQuery ,
QueryClient ,
withDevtools
} from '@tanstack/angular-query-experimental'
// Create a config service
export const DEV_CONFIG = new InjectionToken ( 'DevConfig' , {
factory : () => ({
showDevtools: true ,
position: 'bottom' as const
})
})
export const appConfig : ApplicationConfig = {
providers: [
provideTanStackQuery (
new QueryClient (),
withDevtools (
( config = inject ( DEV_CONFIG )) => ({
initialIsOpen: config . showDevtools ,
position: config . position
}),
{
deps: [ DEV_CONFIG ] // Specify dependencies
}
)
)
]
}
For more control, use injectDevtoolsPanel to manually render DevTools in your own component:
import { Component , ElementRef , viewChild } from '@angular/core'
import { injectDevtoolsPanel } from '@tanstack/angular-query-experimental/devtools-panel'
@ Component ({
selector: 'app-devtools' ,
standalone: true ,
template: `
<div class="devtools-container">
<div class="devtools-header">
<h2>Query DevTools</h2>
<button (click)="closeDevtools()">Close</button>
</div>
<div #devtoolsHost class="devtools-host"></div>
</div>
` ,
styles: [ `
.devtools-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.devtools-header {
padding: 1rem;
background: #1a1a1a;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
}
.devtools-host {
flex: 1;
overflow: auto;
}
` ]
})
export class DevToolsComponent {
devtoolsHost = viewChild . required < ElementRef >( 'devtoolsHost' )
devtoolsRef = injectDevtoolsPanel (() => ({
hostElement: this . devtoolsHost ()
}))
closeDevtools () {
this . devtoolsRef . destroy ()
}
}
The DOM element where DevTools will be rendered.
The QueryClient instance to monitor. Defaults to the injected client.
Error types for filtering.
CSP nonce for inline styles.
Render DevTools in a Shadow DOM.
Callback when DevTools panel is closed.
You can embed TanStack Query DevTools inside your own custom DevTools UI:
custom-devtools.component.ts
import { Component , ElementRef , signal , viewChild } from '@angular/core'
import { injectDevtoolsPanel } from '@tanstack/angular-query-experimental/devtools-panel'
@ Component ({
selector: 'app-custom-devtools' ,
standalone: true ,
template: `
<div class="custom-devtools">
<nav>
<button
[class.active]="activeTab() === 'network'"
(click)="activeTab.set('network')">
Network
</button>
<button
[class.active]="activeTab() === 'query'"
(click)="activeTab.set('query')">
Query Cache
</button>
<button
[class.active]="activeTab() === 'console'"
(click)="activeTab.set('console')">
Console
</button>
</nav>
<div class="tab-content">
@if (activeTab() === 'network') {
<div>Network tab content</div>
}
@if (activeTab() === 'query') {
<div #queryDevtools></div>
}
@if (activeTab() === 'console') {
<div>Console tab content</div>
}
</div>
</div>
` ,
styles: [ `
.custom-devtools {
height: 100%;
display: flex;
flex-direction: column;
}
nav {
display: flex;
background: #2a2a2a;
border-bottom: 1px solid #444;
}
nav button {
padding: 0.75rem 1.5rem;
background: transparent;
border: none;
color: #999;
cursor: pointer;
}
nav button.active {
color: white;
border-bottom: 2px solid #007acc;
}
.tab-content {
flex: 1;
overflow: auto;
}
` ]
})
export class CustomDevToolsComponent {
activeTab = signal < 'network' | 'query' | 'console' >( 'network' )
queryDevtools = viewChild < ElementRef >( 'queryDevtools' )
devtoolsRef = injectDevtoolsPanel (() => ({
hostElement: this . queryDevtools (),
onClose : () => {
// Handle close if needed
}
}))
}
Forcing Production Build
If you need to load DevTools in production (not recommended), import from the production entry point:
import {
provideTanStackQuery ,
QueryClient
} from '@tanstack/angular-query-experimental'
import { withDevtools } from '@tanstack/angular-query-experimental/devtools/production'
export const appConfig : ApplicationConfig = {
providers: [
provideTanStackQuery (
new QueryClient (),
withDevtools (() => ({
loadDevtools: true // Will load even in production
}))
)
]
}
Loading DevTools in production adds ~40KB to your bundle. Only do this for internal tools or staging environments.
Once DevTools are open, you can:
Query List
View all queries with their keys, status, and timestamps
Filter queries by status (fresh, fetching, stale, inactive)
Search queries by key
See query dependencies and relationships
Query Details
Click a query to see:
Data : The current cached data (formatted JSON)
Query Info : Status, timestamps, fetch count, error count
Observers : Number of components watching this query
Actions : Manually refetch, invalidate, or remove the query
Mutation Tracking
View active and recent mutations
See mutation status and variables
Track mutation history
Cache Management
View total cache size
See garbage collection status
Manually clear the entire cache
Troubleshooting
Ensure @tanstack/query-devtools is installed:
npm list @tanstack/query-devtools
Make sure withDevtools() is passed to provideTanStackQuery:
provideTanStackQuery (
new QueryClient (),
withDevtools () // This line
)
By default, DevTools only load when isDevMode() returns true. To force loading:
withDevtools (() => ({
loadDevtools: true
}))
Check for errors in the browser console. Common issues:
“Cannot find module ‘@tanstack/query-devtools’” - Package not installed
CSP violations - Add style-src ‘unsafe-inline’ or use styleNonce
If the DevTools panel opens but shows no queries:
Ensure you’ve created at least one query using injectQuery
Check that the correct QueryClient is being used
Try triggering a query manually to see if it appears
If DevTools slow down your application:
Close DevTools when not actively debugging
Consider using injectDevtoolsPanel to render in a separate window
Reduce the number of queries or use query cancellation
Best Practices
Leave DevTools enabled during development for the best debugging experience. They’re automatically excluded from production builds.
Use Descriptive Query Keys : Makes it easier to find queries in DevTools
// Good
queryKey : [ 'users' , 'list' , { page: 1 , filter: 'active' }]
// Bad
queryKey : [ 'data' ]
Monitor Cache Size : Use DevTools to identify queries that cache too much data
Track Refetch Patterns : Watch for queries that refetch too frequently
Debug Stale Data : Use DevTools to understand when queries become stale
Test Error States : Use DevTools actions to trigger refetches and test error handling
Next Steps
Queries Guide Learn advanced query patterns
Testing Test your queries effectively
SSR Server-side rendering with Angular Query
API Reference Complete DevTools API